Term 2, 2018-19 Software Workshop – II Week 06 – Java Multithreading

Dr Mohammed Bahja [email protected] Credits to: Dr. Mian M. Hamayun Before we start

uAttendance code of today's quiz: ******** uGroups uIn-class test.

Slide #2 of 40 Lecture Objective

The objective of this lecture is to develop a good understanding of concurrency, along with its challenges and how it is implemented using Java Threads.

Slide #3 of 40 Lecture Outline

u Introduction to Concurrency u Threads in Java u States and Life Cycle u Java Executer Service u Thread Synchronization (Monitors) u Deadlocks u Synchronized Collections

Slide #4 of 40 Introduction u Two tasks are operating concurrently, we mean that they’re both making progress at once i.e. simultaneously u Example: Human Body n Respiration, blood circulation, digestion, thinking and walking, all happening in parallel n Similarly, all the senses i.e. sight, hearing, touch, smell and taste, can be in parallel n This parallelism is possible because the human brain is thought to contain billions of “processors.” u Today’s multi-core computers have multiple processors that can perform tasks in parallel.

Slide #5 of 40 Concurrency in Java

u Java programs can have multiple threads of execution, where each thread has its own method-call stack and program counter. u A thread shares application-wide resources such as memory and file handles, with other threads.

Slide #6 of 40 Concurrency in Difficult!

u To see why multithreaded programs can be difficult to write and understand, try the following experiment: Open three books to page 1, and try reading the books concurrently. Read a few words from the first book, then a few from the second, then a few from the third, then loop back and read the next few words from the first book, and so on. After this experiment, you’ll appreciate many of the challenges of multi-threading—switching between the books, reading briefly, remembering your place in each book, moving the book you’re reading closer so that you can see it and pushing the books you’re not reading aside—and, amid all this chaos, trying to comprehend the content of the books!

Slide #7 of 40 Advantages of Multithreading

u Reactive systems – constantly monitoring u More responsive to user input – GUI application can interrupt a time-consuming task u Server can handle multiple clients simultaneously u Can take advantage of parallel processing

Slide #8 of 40 Threads in Java

Creating threads in Java: u Extend java.lang.Thread class n run() method must be overridden (similar to main method of sequential program) n run() is called when execution of the thread begins n A thread terminates when run() returns n start() method invokes run() n Calling run() does not create a new thread OR uImplement java.lang.Runnable interface

Slide #9 of 40 Threads in Java

Creating threads in Java: u Extend java.lang.Thread class OR uImplement java.lang.Runnable interface n If already inheriting another class (i.e., Japplet) n Single method: public void run() n Thread class implements Runnable

Slide #10 of 40 Creating a Thread in Java (Method # 1 example)

u Create a new class derived from the Thread class and override its run() method

public class MyThread extends Thread{ public void run(){ // Code below overrides run() System.out.println("This is my first thread"); } } public class TestMyThread { public static void main(String[] args) { MyThread t = new MyThread(); t.start(); } } }

Slide #11 of 40 Implementing Runnable (Method # 2 example)

public class HelloRunnable implements Runnable{ // implement run method here public void run(){ System.out.println("Thread by implementing

Runnable"); } } public class TestHelloRunnable{ public static void main(String[] args){ HelloRunnable ht = new HelloRunnable(); Thread t = new Thread(ht); t.start(); } }

Slide #12 of 40 The Thread Class

«interface» java.lang.Runnable

java.lang.Thread

+Thread() Creates a default thread.

+Thread(task: Runnable) Creates a thread for a specified task. +start(): void Starts the thread that causes the run() method to be invoked by the JVM. +isAlive(): boolean Tests whether the thread is currently running. +setPriority(p: int): void Sets priority p (ranging from 1 to 10) for this thread. +join(): void Waits for this thread to finish. +sleep(millis: long): void Puts the runnable object to sleep for a specified time in milliseconds. +yield(): void Causes this thread to temporarily pause and allow other threads to execute. +interrupt(): void Interrupts this thread.

Slide #13 of 40 The Static yield() Method

u You can use the yield() method to temporarily release time for other threads.

public void run() { for (int i = 1; i <= lastNum; i++) { System.out.print(" " + i); Thread.yield(); } }

Slide #14 of 40 The Static sleep(milliseconds) Method

u The sleep(long mills) method puts the thread to sleep for the specified time in milliseconds. public void run() { for (int i = 1; i <= lastNum; i++) { System.out.print(" " + i); try { if (i >= 50) Thread.sleep(1); } catch (InterruptedException ex) { } } } u Every time a number (>= 50) is printed, the thread is put to sleep for 1 millisecond.

Slide #15 of 40 The isAlive() Method

u This method used to find out the state of a thread. u returns true: thread is in the Ready, Blocked, or Running state u returns false: thread is new and has not started or if it is finished.

Slide #16 of 40 Interrupts u An interrupt is an indication to a thread that it should stop what it is doing and do something else. u It's up to the programmer to decide exactly how a thread responds to an interrupt, but it is very common for the thread to terminate. u A thread sends an interrupt by invoking interrupt on the Thread object for the thread to be interrupted. n If a thread is currently in the Ready or Running state, its interrupted flag is set; if a thread is currently blocked, it is awakened and enters the Ready state, and an java.io.InterruptedException is thrown. uFor the interrupt mechanism to work correctly, the interrupted thread must support its own interruption.

Slide #17 of 40 Interrupts – Example u An interrupt is an indication to a thread that it should stop what it is doing and do something else.

for (int i = 0; i < inputs.length; i++) { heavyCrunch(inputs[i]); if (Thread.interrupted()) { // We've been interrupted: No more crunching. return; } }

Slide #18 of 40 The join() Method

uYou can use the join() method to force one thread to wait for another thread to finish.

public void run() { Thread Thread Thread thread4 = new Thread( print100 printA new PrintChar('c', 40)); thread4.start(); -char token -char token

try { +getToken +getToken for (int i = 1; i <= lastNum; i++) { +setTokenprintA.join() +setToken System.out.print(" " + i); +paintCompo +paintCompo if (i == 50) thread4.join(); Wait for printA-netchar token net } to finish +mouseClicke +mouseClicke } +getTokend d catch (InterruptedException ex) { +getToken +setToken printA finished u The numbers after 50 are printed after+paintCompone thread printA is } +setToken +paintComponett -char token } finished. +mouseClicked

Slide #19 of 40 Thread Priority

u Each thread is assigned a default priority of Thread.NORM_PRIORITY (constant of 5). You can reset the priority using setPriority(int priority). u Some constants for priorities include n Thread.MIN_PRIORITY n Thread.MAX_PRIORITY n Thread.NORM_PRIORITY u By default, a thread has the priority level of the thread that created it.

Slide #20 of 40 Thread States and Life Cycle

u At any time, a thread is said to be in one of several thread states

Slide #21 of 40 Thread States and Life Cycle u New and Runnable: A new thread begins its life cycle in the new state. It becomes a runnable state, once it is started. u Waiting State: When a thread waits for another thread to perform a task. u Timed Waiting State: A thread enters a timed waiting state i.e. its waiting for an event or a time interval expiry. n Timed waiting threads and waiting threads cannot use a processor, even if its available. u Blocked State: when a thread attempts to perform a task that cannot be completed immediately e.g. I/O u Terminated State: when a thread successfully completes its task or otherwise terminates (due to error etc.)

Slide #22 of 40 Java Executer Service u Creating Concurrent Tasks with Runnable Interface n Implement the Runnable interface with the definition of run method, that contains the code for this thread. u Executing Runnable Objects with an Executor n An Executer Object executes Runnables n It creates and manages a group of threads called a Thread Pool n The Executor interface declares a single method named execute which accepts a Runnable as an argument n The Executor assigns every Runnable passed to its execute method to one of the available threads in the thread pool n If there are no available threads, the Executor creates a new thread or waits for a thread to become available

Slide #23 of 40 Java Executer Service u Executors can reuse existing threads therefore no overhead of creating a new thread u Improve performance by optimizing the number of threads to ensure that the processor stays busy!

«interface» java.util.concurrent.Executor +execute(Runnable object): void Executes the runnable task. \ «interface» java.util.concurrent.ExecutorService +shutdown(): void Shuts down the executor, but allows the tasks in the executor to complete. Once shutdown, it cannot accept new tasks. +shutdownNow(): List Shuts down the executor immediately even though there are unfinished threads in the pool. Returns a list of unfinished tasks. +isShutdown(): boolean Returns true if the executor has been shutdown. +isTerminated(): boolean Returns true if all tasks in the pool are terminated. Slide #24 of 40 Java Executer Service – Example (1 of 4)

Slide #25 of 40 Java Executer Service – Example (2 of 4)

Slide #26 of 40 Java Executer Service – Example (3 of 4)

Slide #27 of 40 Java Executer Service – Example (4 of 4)

Slide #28 of 40 Thread Synchronization class Counter { u When multiple threads share an private int c = 0; public void increment() object and it’s modified by one or { more of them, indeterminate results c++; may occur unless access to the } shared object is managed properly. public void decrement() u In such a case, the program’s { behavior cannot be trusted— c--; } sometimes the program will produce public int value() { the correct results, and sometimes it return c; won’t, and there won’t be any } indication that the shared object } was manipulated incorrectly. What happens if two different threads try to use the increment and decrement methods simultaneously?

Slide #29 of 40 Thread Synchronization

Solution: Only one thread at a time be given exclusive access to the code that accesses the shared object. uDuring that time, other threads desiring to access the object are kept waiting uWhen the thread with exclusive access finishes accessing the object, one of the waiting threads is allowed to proceed. uThis process, called thread synchronization, coordinates access to shared data by multiple concurrent threads. uBy doing so we ensure that the threads have mutually exclusive access to the shared data (critical section problem).

Slide #30 of 40 Monitors in Java

u In Java, every object has a monitor and a monitor (or intrinsic lock) n The monitor ensures that its object’s monitor lock is held by a maximum of only one thread at any time u To specify that a thread must hold a monitor lock to execute a block of code, the code should be placed in a synchronized statement. n Such code is said to be guarded by the monitor lock; a thread must acquire the lock to execute the guarded statements

Slide #31 of 40 Monitors in Java – Synchronized Methods

u In Java, the synchronized keyword can also be used with methods. n A synchronized instance method must acquire the lock on the object that’s used to call the method n A static synchronized method must acquire the lock on the class that’s used to call the method

Slide #32 of 40 Monitors in Java – Synchronized Methods public class SynchronizedCounter { private int c = 0; public synchronized void increment() { c++; } public synchronized void decrement() { c--; } public synchronized int value() { return c; } }

Slide #33 of 40 Monitors in Java – Synchronized Methods

Slide #34 of 40 Deadlocks

u Sometimes two or more threads need to acquire the locks on several shared objects. u This could cause deadlock, in which each thread has the lock on one of the objects and is waiting for the lock on the other object. u In the figure below, the two threads wait for each other to release the in order to get a lock, and neither can continue to run.

Step Thread 1 Thread 2

1 synchronized (object1) {

2 synchronized (object2) { 3 // do something here 4 // do something here 5 synchronized (object2) { 6 synchronized (object1) { // do something here // do something here } } } }

Wait for Thread 2 to Wait for Thread 1 to release the lock on object2 release the lock on object1

Slide #35 of 40 Preventing Deadlocks

u Deadlock can be easily avoided by resource ordering. u With this technique, assign an order on all the objects whose locks must be acquired and ensure that the locks are acquired in that order. u How does this prevent deadlock in the previous example?

Slide #36 of 40 Deadlocks – Another Example (1 of 2)

public class Deadlock { static class Friend { private final String name; public Friend(String name) { this.name = name; } public String getName() { return this.name; } public synchronized void bow(Friend bower) { System.out.format("%s: %s has bowed to me!%n", this.name, bower.getName()); bower.bowBack(this); } public synchronized void bowBack(Friend bower) { System.out.format("%s: %s has bowed back to me!%n", this.name, bower.getName()); } }

Slide #37 of 40 Deadlocks – Another Example (2 of 2)

public static void main(String[] args) { final Friend alphonse = new Friend("Alphonse"); final Friend gaston = new Friend("Gaston");

new Thread(new Runnable() { public void run() { alphonse.bow(gaston); } }).start();

new Thread(new Runnable() { public void run() { gaston.bow(alphonse); } }).start(); } }

Slide #38 of 40 Synchronized Collections

u The classes in the Java Collections Framework are not thread-safe. u Their contents may be corrupted if they are accessed and updated concurrently by multiple threads. u You can protect the data in a collection by locking the collection or using synchronized collections. u The Collections class provides six static methods for creating synchronization wrappers.

java.util.Collections +synchronizedCollection(c: Collection): Collection Returns a synchronized collection. +synchronizedList(list: List): List Returns a synchronized list from the specified list. +synchronizedMap(m: Map): Map Returns a synchronized map from the specified map. +synchronizedSet(s: Set): Set Returns a synchronized set from the specified set. +synchronizedSortedMap(s: SortedMap): SortedMap Returns a synchronized sorted map from the specified sorted map. +synchronizedSortedSet(s: SortedSet): SortedSet Returns a synchronized sorted set.

Slide #39 of 40 Summary

In this lecture, we have been introduced to: uThe notion of concurrency and its importance uHow Threads are created and managed in Java uWhat the different Thread States and its Life Cycle uHow we can use the Executer Service to simply thread management. uWe have briefly looked at Thread Synchronization and Deadlocks. uWe have reviewed the Synchronized Collections.

Slide #40 of 40 References / Links

uChapterth # 23: Concurrency, Java How to Program (10 edition) Early Objects, Deitel & Deitel. uOracle Tutorial: Concurrency, https://docs.oracle.com/javase/tutorial/essential/conc urrency/ uhttps://docs.oracle.com/en/java/javase/11/docs/api/ja va.base/java/lang/Thread.html

Slide #41 of 40