110
CNT 4714: Multi-threaded Applications Page 1 Dr. Mark Llewellyn © CNT 4714: Enterprise Computing Fall 2014 Programming Multithreaded Applications in Java Department of Electrical Engineering and Computer Science Computer Science Division University of Central Florida Instructor : Dr. Mark Llewellyn [email protected] HEC 236, 407-823-2790

CNT 4714: Enterprise Computing Fall 2014 Programming Multithreaded Applications in Java

Embed Size (px)

DESCRIPTION

CNT 4714: Enterprise Computing Fall 2014 Programming Multithreaded Applications in Java. Instructor : Dr. Mark Llewellyn [email protected] HEC 236, 407-823-2790. Department of Electrical Engineering and Computer Science Computer Science Division University of Central Florida. - PowerPoint PPT Presentation

Citation preview

Page 1: CNT 4714: Enterprise Computing Fall 2014 Programming Multithreaded Applications in Java

CNT 4714: Multi-threaded Applications Page 1 Dr. Mark Llewellyn ©

CNT 4714: Enterprise ComputingFall 2014

Programming Multithreaded Applications in Java

CNT 4714: Enterprise ComputingFall 2014

Programming Multithreaded Applications in Java

Department of Electrical Engineering and Computer ScienceComputer Science DivisionUniversity of Central Florida

Instructor : Dr. Mark Llewellyn [email protected]

HEC 236, 407-823-2790

Page 2: CNT 4714: Enterprise Computing Fall 2014 Programming Multithreaded Applications in Java

CNT 4714: Multi-threaded Applications Page 2 Dr. Mark Llewellyn ©

Introduction to Threads in Java• In state-of-the art software, a program can be composed of

multiple independent flows of control.

• A flow of control is more commonly referred to as a process or thread.

• In most of the Java programs that you’ve written (probably) there was a single flow of control. Most console-based programs begin with the first statement of the method main() and work forward to the last statement of the method main(). Flow of control is often temporarily passed to other methods through invocations, but the control returned to main() after their completion.

• Programs with a single control flow are known as sequential processes.

Page 3: CNT 4714: Enterprise Computing Fall 2014 Programming Multithreaded Applications in Java

CNT 4714: Multi-threaded Applications Page 3 Dr. Mark Llewellyn ©

Introduction to Threads in Java (cont.)

• Java supports the creation of programs with concurrent flows of control. These independent flows of control are called threads.

• Threads run within a program and make use of that program’s resources in their execution. For this reason threads are also called lightweight processes (LWP).

• The ability to run more than one process simultaneously is an important characteristic of modern OS such as Linux/Unix and Windows.

– The following two pages show screen shots of a set of applications running on my office PC as well as the set of OS and applications processes required to run those applications.

Page 4: CNT 4714: Enterprise Computing Fall 2014 Programming Multithreaded Applications in Java

CNT 4714: Multi-threaded Applications Page 4 Dr. Mark Llewellyn ©

Applications running on my office PC

Page 5: CNT 4714: Enterprise Computing Fall 2014 Programming Multithreaded Applications in Java

CNT 4714: Multi-threaded Applications Page 5 Dr. Mark Llewellyn ©

CPU working hard!!!

Page 6: CNT 4714: Enterprise Computing Fall 2014 Programming Multithreaded Applications in Java

CNT 4714: Multi-threaded Applications Page 6 Dr. Mark Llewellyn ©

Using Threads To Improve Performance

One Thread

Thread 1

Time

Task 1 Wait for I/O Task 1 Wait for I/O Task 2

Two Threads

Thread 1

Thread 2

Time

Task 1 Wait for I/O Task 1 Wait for I/O

(Idle) Task 2 (Idle) Task 2

Page 7: CNT 4714: Enterprise Computing Fall 2014 Programming Multithreaded Applications in Java

CNT 4714: Multi-threaded Applications Page 7 Dr. Mark Llewellyn ©

Improving Performance With Multithreading

• As the diagram on the previous page implies, applications that perform several tasks which are not dependent on one another will benefit the most from multithreading.

• For example, in the previous diagram, Task 2 can only be overlapped with Task 1 if Task 2 doesn’t depend on the results of Task 1.

• However, some overlap between the two tasks may still be possible even if Task 2 depends on the results of Task 1. In this case the two tasks must communicate so that they can coordinate their operations.

Page 8: CNT 4714: Enterprise Computing Fall 2014 Programming Multithreaded Applications in Java

CNT 4714: Multi-threaded Applications Page 8 Dr. Mark Llewellyn ©

Improving Performance With Multithreading (cont.)

• Writing multithreaded programs can be tricky and complicated, particularly when synchronization between threads is required.

• Although the human mind can perform many functions concurrently, people find it difficult to jump between parallel trains of thought.

• To see why multithreading can be difficult to program and understand, try the experiment shown on the following page.

Page 9: CNT 4714: Enterprise Computing Fall 2014 Programming Multithreaded Applications in Java

CNT 4714: Multi-threaded Applications Page 9 Dr. Mark Llewellyn ©

Multithreading Experiment

Page 1

Page 2

Page 3

In this chapter, we introduce Swing components that enable developers to build functionally rich user interfaces.

The Swing graphical interface components were introduced with the Java Foundation Classes (JFC) as a downloadable extension to the Java 1.1 Platform, then became a standard extension with the Java 2 Platform.

Swing provides a more complete set of GUI components than the Abstract Windowing Toolkit (AWT), including advanced features such as a pluggable look and feel, lightweight component rendering and drag-and-drop capabilities.

The experiment: Try reading the pages above concurrently by reading a few words from the first page, then a few words from the second page, then a few words from the third page, then loop back and read a few words from the first page, and so on. Does anything make sense? Can you construct a single sentence from what you have read? Can you remember on which page a particular word appeared? Can you even remember when you get back to the first page where you left off?

Page 10: CNT 4714: Enterprise Computing Fall 2014 Programming Multithreaded Applications in Java

CNT 4714: Multi-threaded Applications Page 10 Dr. Mark Llewellyn ©

Typical Multithreaded Applications

• Used to improve the performance of applications which require extensive I/O operations.

• Useful in improving the responsiveness of GUI-based applications.

• Used when two or more clients need to run server-based applications simultaneously.

Note: on a single CPU machine, threads don’t actually execute simultaneously. Part of the JVM known as the thread scheduler time-slices threads which are runnable (we’ll see more of this in a bit) giving the illusion of simultaneous execution.

Page 11: CNT 4714: Enterprise Computing Fall 2014 Programming Multithreaded Applications in Java

CNT 4714: Multi-threaded Applications Page 11 Dr. Mark Llewellyn ©

A multithreaded program ends when all of its individual flows of control (threads) end.

Multithreaded Program { statement 1; statement 2; … statement x; … statement y; … statement z;}

Thread B { B statement 1; B statement 2; … statement r;}

Thread C { C statement 1; C statement 2; … C statement t;}

Thread A { A statement 1; A statement 2; … A statement m; … A statement n;}

This statement starts thread B. After starting the thread, the program continues with the next statement.

This statement starts thread A. After starting thread A, the program continues with the next statement.

This statement in thread A starts thread C. Thread A continues with next statement.

Page 12: CNT 4714: Enterprise Computing Fall 2014 Programming Multithreaded Applications in Java

CNT 4714: Multi-threaded Applications Page 12 Dr. Mark Llewellyn ©

Thread A

Thread B

Thread C

Thread Execution in a Multiprocessor Environment

Thread C

Thread B

Thread A

Thread Execution in a Uniprocessor Environment

Page 13: CNT 4714: Enterprise Computing Fall 2014 Programming Multithreaded Applications in Java

CNT 4714: Multi-threaded Applications Page 13 Dr. Mark Llewellyn ©

The Java Thread Class

java.lang.Runnable

java.lang.Thread

+Thread()

+Thread (target: Runnable)

+run(): void

+start(): void

+interrupt(): void

+isAlive(): boolean

+setPriority(p: int): void

+join(): void

+sleep(millis: long): void

+yield(): void

+isInterrupted(): boolean

+currentThread(): Thread

Creates a default thread.

Invoked by the JVM to execute the thread. You must override this method and provide the code you want your thread to execute in your thread class. This method is never directly invoked by a the runnable object in a program, although it is an instance method of a runnable object.

Starts the thread that causes the run() method to be invoked by the JVM

Interrupts this thread. If the thread is blocked, it is ready to run again.

Tests if the thread is currently running.

Sets priority p (ranging from 1 to 10) for this thread.

Waits for this thread to finish.

Puts the runnable object to sleep for a specified time in milliseconds.

Creates a new thread to run the target object

Causes this thread to temporarily pause and allow other threads to execute

Tests if the current thread has been interrupted

Returns a reference to the currently executing thread object.

Page 14: CNT 4714: Enterprise Computing Fall 2014 Programming Multithreaded Applications in Java

CNT 4714: Multi-threaded Applications Page 14 Dr. Mark Llewellyn ©

Java Classes and Threads

• Java has several classes that support the creation and scheduling of threads.

• The two basic ways of creating threads in Java are:

– 1) extending the Thread class

– or 2) implementing the Runnable interface.

(Both are found in package java.lang. Thread actually implements Runnable.)

• We’ll also look at a slightly different technique for creating and scheduling threads later using the java.util.Timer and java.util.TimerTask classes.

Page 15: CNT 4714: Enterprise Computing Fall 2014 Programming Multithreaded Applications in Java

CNT 4714: Multi-threaded Applications Page 15 Dr. Mark Llewellyn ©

Java Classes and Threads (cont.)

• The following two simple examples, illustrate the differences in creating threads using these two different techniques.

• The example is simple, three threads are created, one that prints the character ‘A’ twenty times, one that prints the character ‘B’ twenty times, and a third thread that prints the integer numbers from 1 to 20.

• The first program is an example of extending the thread class. The second program is an example of using the Runnable interface. This latter technique is the more common and preferred technique. While we will see more examples of this technique later, this simple example will illustrate the difference in the two techniques.

Page 16: CNT 4714: Enterprise Computing Fall 2014 Programming Multithreaded Applications in Java

CNT 4714: Multi-threaded Applications Page 16 Dr. Mark Llewellyn ©

//Custom Thread ClassPublic class CustomThread extends Thread{ … public CustomThread(…) { … } //Override the run method in Thread //Tell system how to run custom thread public void run( ) { … } …} //end CustomThread Class

//Client Class to utilize CustomThreadPublic class Client{ … public void someMethod( ) { … //create a thread CustomThread thread1 =

new CustomThread(…); //start a thread thread1.start( ); …

//create another thread CustomThread thread2 = new CustomThread(…); //start another thread thread2.start( ); … }…} //end Client Class

Template for defining a thread class by extending the Thread class. Threads thread1 and thread2 are runnable objects created from the CustomThread class. The start method informs the system that the thread is ready to run.

Page 17: CNT 4714: Enterprise Computing Fall 2014 Programming Multithreaded Applications in Java

CNT 4714: Multi-threaded Applications Page 17 Dr. Mark Llewellyn ©

//Custom Thread ClassPublic class CustomThread implements Runnable{ … public CustomThread(…) { … } //Implement the run method in Runnable //Tell system how to run custom thread public void run( ) { … } …} //end CustomThread Class

//Client Class to utilize CustomThreadPublic class Client{ … public void someMethod( ) { … //create an instance of CustomThread CustomThread custhread =

new CustomThread(…); … //create a thread Thread thread =

newThread(custhread); … //start a thread thread.start( ); … }…} //end Client Class

Template for defining a thread class by implementing the Runnable interface. To start a new thread with the Runnable interface, you must first create an instance of the class that implements the Runnable interface (in this case custhread), then use the Thread class constructor to construct a thread.

Page 18: CNT 4714: Enterprise Computing Fall 2014 Programming Multithreaded Applications in Java

CNT 4714: Multi-threaded Applications Page 18 Dr. Mark Llewellyn ©

Start thread execution after a 0 msec delay

(i.e., immediately)

//Class to generate threads by extending the Thread classpublic class TestThread { // Main method public static void main(String[] args) { // Create threads PrintChar printA = new PrintChar('a', 20); PrintChar printB = new PrintChar('b', 20); PrintNum print20 = new PrintNum(20);

// Start threads print20.start(); printA.start(); printB.start(); }}

// The thread class for printing a specified character a specified number of timesclass PrintChar extends Thread { private char charToPrint; // The character to print private int times; // The times to repeat

// Construct a thread with specified character and number of times to print the character public PrintChar(char c, int t) { charToPrint = c; times = t; }

Extension of the Thread class

Page 19: CNT 4714: Enterprise Computing Fall 2014 Programming Multithreaded Applications in Java

CNT 4714: Multi-threaded Applications Page 19 Dr. Mark Llewellyn ©

// Override the run() method to tell the system what the thread will do public void run() { for (int i = 0; i < times; i++) System.out.print(charToPrint); }}

// The thread class for printing number from 1 to n for a given nclass PrintNum extends Thread { private int lastNum;

// Construct a thread for print 1, 2, ... i public PrintNum(int n) { lastNum = n; }

// Tell the thread how to run public void run() { for (int i = 1; i <= lastNum; i++) System.out.print(" " + i); }} //end class TestThread

Overriding the run method in the Thread class

Page 20: CNT 4714: Enterprise Computing Fall 2014 Programming Multithreaded Applications in Java

CNT 4714: Multi-threaded Applications Page 20 Dr. Mark Llewellyn ©

Sam

ple executions of class TestT

hread. Notice

that the o

utput from the

three threads is inte

rleaved. Also no

tice that the output sequence is not repe

atable.

Page 21: CNT 4714: Enterprise Computing Fall 2014 Programming Multithreaded Applications in Java

CNT 4714: Multi-threaded Applications Page 21 Dr. Mark Llewellyn ©

Main method simple creates a new Runnable object and terminates.

//Class to generate threads by implementing the Runnable interfacepublic class TestRunnable { // Create threads Thread printA = new Thread(new PrintChar('a', 20)); Thread printB = new Thread(new PrintChar('b', 20)); Thread print20 = new Thread(new PrintNum(20));

public static void main(String[] args) { new TestRunnable(); }

public TestRunnable() { // Start threads print20.start(); printA.start(); printB.start(); }

// The thread class for printing a specified character in specified times class PrintChar implements Runnable { private char charToPrint; // The character to print private int times; // The times to repeat

// Construct a thread with specified character and number of times to print the character public PrintChar(char c, int t) { charToPrint = c; times = t; }

Runnable object starts thread execution.

Implements the Runnable interface.

Page 22: CNT 4714: Enterprise Computing Fall 2014 Programming Multithreaded Applications in Java

CNT 4714: Multi-threaded Applications Page 22 Dr. Mark Llewellyn ©

// Override the run() method to tell the system what the thread will do public void run() { for (int i = 0; i < times; i++) System.out.print(charToPrint); } }

// The thread class for printing number from 1 to n for a given n class PrintNum implements Runnable { private int lastNum;

// Construct a thread for print 1, 2, ... i public PrintNum(int n) { lastNum = n; }

// Tell the thread how to run public void run() { for (int i = 1; i <= lastNum; i++) System.out.print(" " + i); } }} //end class TestRunnable

Override the run method for both types of threads.

Page 23: CNT 4714: Enterprise Computing Fall 2014 Programming Multithreaded Applications in Java

CNT 4714: Multi-threaded Applications Page 23 Dr. Mark Llewellyn ©

Sam

ple executions of class TestR

unnable. N

otice that the output

from the three thread

s is interleaved. A

lso no

tice that the output sequen

ce is not repeatable

.

Page 24: CNT 4714: Enterprise Computing Fall 2014 Programming Multithreaded Applications in Java

CNT 4714: Multi-threaded Applications Page 24 Dr. Mark Llewellyn ©

Some Modifications to the Example• To illustrate some of the methods in the Thread class, you

might want to try a few modifications to the TestRunnable class in the previous example. Notice how the modifications change the order of the numbers and characters in the output.

• Use the yield() method to temporarily release time for other threads to execute. Modify the code in the run method in PrintNum class to the following:

– Now every time a number is printed, the print20 thread yields, so each number will be followed by some characters.

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

Page 25: CNT 4714: Enterprise Computing Fall 2014 Programming Multithreaded Applications in Java

CNT 4714: Multi-threaded Applications Page 25 Dr. Mark Llewellyn ©

Some Modifications to the Example (cont.)

• The sleep(long millis) method puts the thread to sleep for the specified time in milliseconds. Modify the code in the run method in PrintNum class to the following:

– Now every time a number greater than 10 is printed, the print20 thread is put to sleep for 2 milliseconds, so all the characters will complete printing before the last integer is printed.

public void run() { for (int i = 1; i <= lastNum; i++) { System.out.print(" " + i); try { if (i >= 10) Thread.sleep(2); } catch (InterruptedException ex) { } }}

Page 26: CNT 4714: Enterprise Computing Fall 2014 Programming Multithreaded Applications in Java

CNT 4714: Multi-threaded Applications Page 26 Dr. Mark Llewellyn ©

Some Modifications to the Example (cont.)

• You can use the join() method to force one thread to wait for another thread to finish. Modify the code in the run method in PrintNum class to the following:

– Now the numbers greater than 10 are printed only after thread printA is finished.

public void run() { for (int i = 1; i <= lastNum; i++) { System.out.print(" " + i); try { if (i == 10) printA.join(); } catch (InterruptedException ex) { } }}

Page 27: CNT 4714: Enterprise Computing Fall 2014 Programming Multithreaded Applications in Java

CNT 4714: Multi-threaded Applications Page 27 Dr. Mark Llewellyn ©

Other Java Classes and Threads

• We noted earlier that Java has several different classes that support the creation and scheduling of threads. Classes java.util.Timer and java.util.TimerTask are generally the easiest to use. They allow a thread to be created and run either at a time relative to the current time or at some specific time.

• We’ll look at these classes briefly and give a couple of examples.

Page 28: CNT 4714: Enterprise Computing Fall 2014 Programming Multithreaded Applications in Java

CNT 4714: Multi-threaded Applications Page 28 Dr. Mark Llewellyn ©

Java Classes and Threads (cont.)

• Class Timer overloads the schedule() method three times for creating threads after either some specified delay or at some specific time.

– public void schedule(TimerTask task, long m);

• Runs task.run() after waiting m milliseconds.

– public void schedule(TimerTask task, long m, long n);

• Runs task.run() after waiting m milliseconds, then repeats it every n milliseconds.

– Public void schedule(TimerTask task, Date t);

• Runs task.run() at the time indicated by date t.

• By extending the abstract class TimerTask and specifying a definition for its abstract method run(), an application-specific thread can be created.

Page 29: CNT 4714: Enterprise Computing Fall 2014 Programming Multithreaded Applications in Java

CNT 4714: Multi-threaded Applications Page 29 Dr. Mark Llewellyn ©

Example – Thread Execution After a Delay

• The code listing on the following page gives a very simple example of executing a thread after a delay (using the first schedule() method from the previous page).

• The thread in this example, simply prints a character 10 times and then ends.

• Look at the code and follow the flow, then execute it on your machine (code appears on the course webpage).

Page 30: CNT 4714: Enterprise Computing Fall 2014 Programming Multithreaded Applications in Java

CNT 4714: Multi-threaded Applications Page 30 Dr. Mark Llewellyn ©

//displays characters in separate threadsimport java.util.*;public class DisplayCharSequence extends TimerTask { private char displayChar; Timer timer; //constructor for character displayer public DisplayCharSequence(char c){ displayChar = c; timer = new Timer(); timer.schedule(this, 0); }

//display the occurrences of the character public void run() { for (int i = 0; i < 10; ++i) { System.out.print(displayChar); } timer.cancel(); }

//main public static void main (String[] args) { DisplayCharSequence s1 = new DisplayCharSequence(‘M’); DisplayCharSequence s2 = new DisplayCharSequence(‘A’); DisplayCharSequence s3 = new DisplayCharSequence(‘R’); DisplayCharSequence s4 = new DisplayCharSequence(‘K’); }}

Start thread execution after a 0 msec delay

(i.e., immediately)

A subclass implementation of TimerTask’s abstract method run() has typically two parts – first part is application specific (what the thread is supposed to do) and the second part ends the thread.

Page 31: CNT 4714: Enterprise Computing Fall 2014 Programming Multithreaded Applications in Java

CNT 4714: Multi-threaded Applications Page 31 Dr. Mark Llewellyn ©

It worked right!!!

Page 32: CNT 4714: Enterprise Computing Fall 2014 Programming Multithreaded Applications in Java

CNT 4714: Multi-threaded Applications Page 32 Dr. Mark Llewellyn ©

Example – Repeated Thread Execution

• This next example demonstrates how to schedule a thread to run multiple times. Basically, the thread updates a GUI-based clock every second.

Sample GUI

Page 33: CNT 4714: Enterprise Computing Fall 2014 Programming Multithreaded Applications in Java

CNT 4714: Multi-threaded Applications Page 33 Dr. Mark Llewellyn ©

//displays current time – threaded executionimport java.util.*;import javax.swing.JFrame;import java.text.*;import java.awt.*;

public class BasicClock extends TimerTask { final static long MILLISECONDS_PER_SECOND = 1000; private JFrame window = new JFrame(“Basic Clock”); private Timer timer = new Timer(); private String clockFace = “”; //constructor for clock public BasicClock(){ //set up GUI window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); window.setSize(200,60); Container c = window.getContentPane(); c.setBackground(Color.WHITE); window.setVisible(true); //update GUI every second beginning immediately timer.schedule(this,0,1*MILLISECONDS_PER_SECOND); }

Two tasks: (1) configure the GUI and (2) schedule the thread to update the GUI-clock every second.

This form of the overloaded schedule() method is the second one shown on page 28 which uses a delay and a repetition factor.

Page 34: CNT 4714: Enterprise Computing Fall 2014 Programming Multithreaded Applications in Java

CNT 4714: Multi-threaded Applications Page 34 Dr. Mark Llewellyn ©

//display updated clock public void run(){ Date time = new Date(); Graphics g = window.getContentPane().getGraphics(); g.setColor(Color.WHITE); g.drawString(clockFace, 10, 20); clockFace = time.toString(); g.setColor(Color.BLUE); g.drawString(clockFace,10, 20);}

//main public static void main (String[] args) { BasicClock clock = new BasicClock(); }}

Date() returns current time to the millisecond. toString() method returns a textual representation of the date in the form: w c d h:m:s z yWhere: w: 3 char-rep of day of week c: 3 char-rep of month d: 2 digit-rep of day of month h: 2 digit-rep of hour m: 2 digit-rep of minute within hr s: 2 digit-rep of second within min z: 3 char-rep of time zone y: 4 char-rep of year

Page 35: CNT 4714: Enterprise Computing Fall 2014 Programming Multithreaded Applications in Java

CNT 4714: Multi-threaded Applications Page 35 Dr. Mark Llewellyn ©

!! CAUTION !!

• Java provides two different standard classes named Timer. The class we’ve used in the past two examples is part of the util API. There is also a Timer class that is part of the swing API.

• In our previous example, we needed to make sure that we didn’t inadvertently bring both Timer classes into our program which would have created an ambiguity about which Timer class was being used.

• Although you cannot import both Timer classes into a single Java source file, you can use both Timer classes in the same Java source file. An import statement exists to allow a syntactic shorthand when using Java resources; i.e., an import statement is not required to make use of Java resources. Using fully qualified class names will remove the ambiguity.

– java.util.Time t1 = new java.util.Timer();

– javax.swing.Timer t2 = new javax swing.Timer();

Page 36: CNT 4714: Enterprise Computing Fall 2014 Programming Multithreaded Applications in Java

CNT 4714: Multi-threaded Applications Page 36 Dr. Mark Llewellyn ©

Example – Thread Execution At Specific Time

• This next example demonstrates how to schedule a thread to run at a specific time. This example will create a couple of threads to remind you of impending appointments. Basically, the thread pops-up a window to remind you of the appointment.

This window popsup 6 minutes

later

Sample DisplayAlert

Window

Page 37: CNT 4714: Enterprise Computing Fall 2014 Programming Multithreaded Applications in Java

CNT 4714: Multi-threaded Applications Page 37 Dr. Mark Llewellyn ©

Third version of schedule() method as shown on page 28.

Page 38: CNT 4714: Enterprise Computing Fall 2014 Programming Multithreaded Applications in Java

CNT 4714: Multi-threaded Applications Page 38 Dr. Mark Llewellyn ©

Sleeping• In the three examples so far, all the threads performed some

action. Threads are also used to pause a program for some period of time.

• Standard class java.lang.Thread has a class method sleep() for pausing the flow of control.

public static void sleep (long n) throws InterruptedException

• For example, the following code segment will twice get and display the current time, but the time acquisitions are separated by 10 seconds by putting the process to sleep.

Page 39: CNT 4714: Enterprise Computing Fall 2014 Programming Multithreaded Applications in Java

CNT 4714: Multi-threaded Applications Page 39 Dr. Mark Llewellyn ©

Put the process to sleep for 10 seconds.

Page 40: CNT 4714: Enterprise Computing Fall 2014 Programming Multithreaded Applications in Java

CNT 4714: Multi-threaded Applications Page 40 Dr. Mark Llewellyn ©

Notice that the process has slept for exactly 10 seconds in each case.

Page 41: CNT 4714: Enterprise Computing Fall 2014 Programming Multithreaded Applications in Java

CNT 4714: Multi-threaded Applications Page 41 Dr. Mark Llewellyn ©

Life Cycle of a Thread• At any given point in time, a thread is said to be in one of several

thread states as illustrated in the diagram below.

NEW

Terminated

Runnable

Blocked

Waiting

wait()

notify() or notifyAll()

interrupt()

signalstart()

run() terminates

Non-executing threads

Page 42: CNT 4714: Enterprise Computing Fall 2014 Programming Multithreaded Applications in Java

CNT 4714: Multi-threaded Applications Page 42 Dr. Mark Llewellyn ©

Life Cycle of a Thread (cont.)

NEW

Terminated

Runnable

Blocked

Waiting

The thread constructor is called to create a new instance of the Thread class.

1

Page 43: CNT 4714: Enterprise Computing Fall 2014 Programming Multithreaded Applications in Java

CNT 4714: Multi-threaded Applications Page 43 Dr. Mark Llewellyn ©

Life Cycle of a Thread (cont.)

NEW

Terminated

Runnable

Blocked

Waiting

start()

The start() method is invoked to designate the thread as runnable.2

Page 44: CNT 4714: Enterprise Computing Fall 2014 Programming Multithreaded Applications in Java

CNT 4714: Multi-threaded Applications Page 44 Dr. Mark Llewellyn ©

Life Cycle of a Thread (cont.)

NEW

Terminated

Runnable

Blocked

Waiting

3The Java thread scheduler runs the thread as the processor becomes available

Page 45: CNT 4714: Enterprise Computing Fall 2014 Programming Multithreaded Applications in Java

CNT 4714: Multi-threaded Applications Page 45 Dr. Mark Llewellyn ©

Life Cycle of a Thread (cont.)

NEW

Terminated

Runnable

Blocked

Waiting

5If the thread invokes the wait() method, it is put into the waiting state and will remain there until another thread invokes the notify() or notifyAll() method.

Page 46: CNT 4714: Enterprise Computing Fall 2014 Programming Multithreaded Applications in Java

CNT 4714: Multi-threaded Applications Page 46 Dr. Mark Llewellyn ©

Life Cycle of a Thread (cont.)

NEW

Terminated

Runnable

Blocked

Waiting

6The thread ends when the run method terminates.

Page 47: CNT 4714: Enterprise Computing Fall 2014 Programming Multithreaded Applications in Java

CNT 4714: Multi-threaded Applications Page 47 Dr. Mark Llewellyn ©

Life Cycle of a Thread (cont.)

NEW

Terminated

Runnable

Blocked

Waiting

4

The thread can become blocked for various reasons and will not run again until it is returned to the runnable state.

Page 48: CNT 4714: Enterprise Computing Fall 2014 Programming Multithreaded Applications in Java

CNT 4714: Multi-threaded Applications Page 48 Dr. Mark Llewellyn ©

Summary of States In The Life Cycle of a Thread

State Description

NewThe thread has been created (its constructor has been invoked), but not yet started.

Runnable

The thread’s start() method has been invoked and the thread is available to be run by the thread scheduler. A thread in the Runnable state may actually be running, or it may be waiting in the thread queue for an opportunity to run.

Blocked

The thread has been temporarily removed from the Runnable state so that it cannot be executed. This can happen if the thread’s sleep() method is invoked, if the thread is waiting on I/O, or if the thread requests a lock on an object that is already locked. When the condition changes, the thread will be returned to the Runnable state.

WaitingThe thread has invoked its wait() method so that other threads can access an object. The thread will remain in the Waiting state until another thread invokes the notify() or notifyAll() method.

Terminated The thread’s run() method has ended.

Page 49: CNT 4714: Enterprise Computing Fall 2014 Programming Multithreaded Applications in Java

CNT 4714: Multi-threaded Applications Page 49 Dr. Mark Llewellyn ©

Life Cycle of a Thread – A Slightly Different View

• At any given point in time, a thread is said to be in one of several thread states as illustrated in the diagram below.

terminated

running

readynew

blocked

Threadcreated

start()

run()yield() or tim

eout run() returns

Wait for target to finish

Wait for timeoutWait to be

notified

sleep()

wait()interrupt()target

finished

interrupt()

notify() or notifyAll()

join()

timeout

Page 50: CNT 4714: Enterprise Computing Fall 2014 Programming Multithreaded Applications in Java

CNT 4714: Multi-threaded Applications Page 50 Dr. Mark Llewellyn ©

Life Cycle of a Thread (cont.)

• A new thread begins its life cycles in the new state. It remains in this state until the program starts the thread, which places the thread in the ready state (also commonly referred to as the runnable state). A thread in this state is considered to be executing its task, although at any given moment it may not be actually executing.

• When a ready thread begins execution, it enters the running state. A running thread may return to the ready state if its CPU time slice expires or its yield() method is invoked.

• A thread can enter the blocked state (i.e., it becomes inactive) for several reasons. It may have invoked the join(), sleep(), or wait() method, or some other thread may have invoked these methods. It may be waiting for an I/O operation to complete.

• A blocked thread can be reactivated when the action which inactivated it is reversed. For example, if a thread has been put to sleep and the sleep time has expired, the thread is reactivated and enters the ready state.

Page 51: CNT 4714: Enterprise Computing Fall 2014 Programming Multithreaded Applications in Java

CNT 4714: Multi-threaded Applications Page 51 Dr. Mark Llewellyn ©

Life Cycle of a Thread (cont.)

• A thread is terminated if it completes the execution of its run() method.

• The isAlive() method is used to query the state of a thread. This method returns true it a thread is in the ready, blocked, or running state; it returns false if a thread is new and has not started or if it is finished.

• The interrupt() method interrupts a thread in the following way: 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 a java.lang.InterruptedException is thrown.

• Threads typically sleep when they momentarily do not have work to perform. Example, a word processor may contain a thread that periodically writes a copy of the current document to disk for recovery purposes.

Page 52: CNT 4714: Enterprise Computing Fall 2014 Programming Multithreaded Applications in Java

CNT 4714: Multi-threaded Applications Page 52 Dr. Mark Llewellyn ©

Life Cycle of a Thread (cont.)

• A runnable thread enters the terminated state when it completes its task or otherwise terminates (perhaps due to an error condition).

• At the OS level, Java’s runnable state actually encompasses two separate states. The OS hides these two states from the JVM, which sees only the runnable state.

– When a thread first transitions to the runnable state from the new state, the thread is in the ready state. A ready thread enters the running state (i.e., begins execution) when the OS assigns the thread to a processor (this is called dispatching the thread). In most OS, each thread is given a small amount of processor time – called a quantum or time slice – with which to perform its task. When the thread’s quantum expires, the thread returns to the ready state and the OS assigns another thread to the processor. Transitions between these states are handled solely by the OS.

Page 53: CNT 4714: Enterprise Computing Fall 2014 Programming Multithreaded Applications in Java

CNT 4714: Multi-threaded Applications Page 53 Dr. Mark Llewellyn ©

Thread Priorities

• Every Java thread has a priority that helps the OS determine the order in which threads are scheduled.

• Java priorities are in the range between MIN_PRIORITY (a constant of 1) and MAX_PRIORITY (a constant of 10).

• Threads with a higher priority are more important to a program and should be allocated processor time before lower-priority threads. However, thread priorities cannot guarantee the order in which threads execute.

• By default, every thread is given priority NORM_PRIORITY (a constant of 5). Each new thread inherits the priority of the thread that created it.

Page 54: CNT 4714: Enterprise Computing Fall 2014 Programming Multithreaded Applications in Java

CNT 4714: Multi-threaded Applications Page 54 Dr. Mark Llewellyn ©

Priority 9

Priority 8

Priority 7

Priority 10

Priority 6

Priority 5

Priority 4

Priority 3

Priority 2

Priority 1

A B

D

C

E F

G

H I

J K

Ready threads

Thread.MIN_PRIORITY

Thread.MAX_PRIORITY

Thread.NORM_PRIORITY

Thread Priority Scheduling

Page 55: CNT 4714: Enterprise Computing Fall 2014 Programming Multithreaded Applications in Java

CNT 4714: Multi-threaded Applications Page 55 Dr. Mark Llewellyn ©

Creating and Executing Threads• In J2SE 5.0 and above, the preferred means of creating a

multithreaded application is to implement the Runnable interface (package java.lang) (see earlier examples also) and use built-in methods and classes to create Threads that execute the Runnable interface.

• The Runnable interface declares a single method named run(), Runnables are executed by an object of a class that implements the Executor interface (package java.util.concurrent). This interface declares a single method named execute.

• An Executor object typically creates and manages a group of threads called a thread pool. These threads execute the Runnable objects passed to the execute method.

Page 56: CNT 4714: Enterprise Computing Fall 2014 Programming Multithreaded Applications in Java

CNT 4714: Multi-threaded Applications Page 56 Dr. Mark Llewellyn ©

Creating and Executing Threads (cont.)

• The Executor assigns each Runnable to one of the available threads in the thread pool. If there are no available threads in the thread pool, the Executor creates a new thread or waits for a thread to become available and assigns that thread the Runnable that was passed to method execute.

• Depending on the Executor type, there may be a limit to the number of threads that can be created. Interface ExecutorService (package java.util.concurrent) is a subinterface of Executor that declares a number of other methods for managing the life cycle of the Executor. An object that implements this ExecutorService interface can be created using static methods declared in class Executors (package java.util.concurrent). The next examples illustrates these.

Page 57: CNT 4714: Enterprise Computing Fall 2014 Programming Multithreaded Applications in Java

CNT 4714: Multi-threaded Applications Page 57 Dr. Mark Llewellyn ©

Multithreading Example – Sleeping/Waking Threads

// PrintTask class sleeps for a random time from 0 to 5 secondsimport java.util.Random;

public class PrintTask implements Runnable { private int sleepTime; // random sleep time for thread private String threadName; // name of thread private static Random generator = new Random(); // assign name to thread public PrintTask( String name ) { threadName = name; // set name of thread // pick random sleep time between 0 and 5 seconds sleepTime = generator.nextInt( 5000 ); } // end PrintTask constructor

Page 58: CNT 4714: Enterprise Computing Fall 2014 Programming Multithreaded Applications in Java

CNT 4714: Multi-threaded Applications Page 58 Dr. Mark Llewellyn ©

Multithreading Example – Sleeping/Waking Threads

// method run is the code to be executed by new thread public void run() { try // put thread to sleep for sleepTime amount of time

{ System.out.printf( "%s going to sleep for %d milliseconds.\n", threadName, sleepTime ); Thread.sleep( sleepTime ); // put thread to sleep } // end try // if thread interrupted while sleeping, print stack trace catch ( InterruptedException exception ) {

exception.printStackTrace(); } // end catch // print thread name System.out.printf( "%s done sleeping\n", threadName ); } // end method run} // end class PrintTask

Page 59: CNT 4714: Enterprise Computing Fall 2014 Programming Multithreaded Applications in Java

CNT 4714: Multi-threaded Applications Page 59 Dr. Mark Llewellyn ©

Multithreading Example – Create Threads and Execute// Multiple threads printing at different intervals.import java.util.concurrent.Executors;import java.util.concurrent.ExecutorService;public class RunnableTester { public static void main( String[] args ) { // create and name each runnable PrintTask task1 = new PrintTask( "thread1" ); PrintTask task2 = new PrintTask( "thread2" ); PrintTask task3 = new PrintTask( "thread3" ); System.out.println( "Starting threads" );

// create ExecutorService to manage threads ExecutorService threadExecutor = Executors.newCachedThreadPool(); // start threads and place in runnable state threadExecutor.execute( task1 ); // start task1 threadExecutor.execute( task2 ); // start task2 threadExecutor.execute( task3 ); // start task3

threadExecutor.shutdown(); // shutdown worker threads System.out.println( "Threads started, main ends\n" ); } // end main} // end class RunnableTester

Page 60: CNT 4714: Enterprise Computing Fall 2014 Programming Multithreaded Applications in Java

CNT 4714: Multi-threaded Applications Page 60 Dr. Mark Llewellyn ©

Example Executions of RunnableTester.java

Page 61: CNT 4714: Enterprise Computing Fall 2014 Programming Multithreaded Applications in Java

CNT 4714: Multi-threaded Applications Page 61 Dr. Mark Llewellyn ©

More Sophisticated Threading• All of the example applications up to this point involved

threads which were unsynchronized. None of the threads actually needed to communicate with one another and they did not require access to a shared object.

• The threads we’ve seen so far fall into the category of unrelated threads. These are threads which do different tasks and do not interact with one another.

• A slightly more complex form of threading involves threads which are related but unsynchronized. In this case, multiple threads operate on different pieces of the same data structure. An example of this type of threading is illustrated on the next page with a threaded program to determine if a number is prime.

Page 62: CNT 4714: Enterprise Computing Fall 2014 Programming Multithreaded Applications in Java

CNT 4714: Multi-threaded Applications Page 62 Dr. Mark Llewellyn ©

//class for threaded prime number testing//no inheritance issues so using the simple form of thread creationclass testRange extends Thread { static long possPrime; long from, to; //test range for a thread //constructor //record the number to be tested and the range to be tried testRange(int argFrom, long argpossPrime) { possPrime = argpossPrime; if (argFrom ==0) from = 2; else from = argFrom; to=argFrom+99; } //implementation of run public void run() { for (long i=from; i <= to && i<possPrime; i++) { if (possPrime % i == 0) { //i divides possPrime exactly System.out.println("factor " + i + " found by thread " + getName() ); break; //exit for loop immediately } yield(); //suspend thread } }}

Prime Number Tester Class

Page 63: CNT 4714: Enterprise Computing Fall 2014 Programming Multithreaded Applications in Java

CNT 4714: Multi-threaded Applications Page 63 Dr. Mark Llewellyn ©

//driver class to demonstrate threaded prime number testerpublic class testPrime { public static void main (String s[]) {

//number to be tested for primality is entered as a command line argument //examples: 5557 is prime, 6841 is prime, 6842 is not prime long possPrime = Long.parseLong(s[0]);

int centuries = (int) (possPrime/100) + 1; for (int i=0; i<centuries;i++) { new testRange(i*100, possPrime).start(); }

}}

Driver Class for Prime Number Tester

• This is an example of related but unsynchronized threads. In this case the threads are related since they are each working on a piece of the same data, but approach it from a slightly different perspective. However, they are unsynchronized since they do not share information.

Page 64: CNT 4714: Enterprise Computing Fall 2014 Programming Multithreaded Applications in Java

CNT 4714: Multi-threaded Applications Page 64 Dr. Mark Llewellyn ©

2048 and 6842 are not prime – their factors are shown by the thread which discovered the factor.

5557 is prime so no thread will find a factor

Page 65: CNT 4714: Enterprise Computing Fall 2014 Programming Multithreaded Applications in Java

CNT 4714: Multi-threaded Applications Page 65 Dr. Mark Llewellyn ©

Related and Synchronized Threads• The most complicated type of threaded application involves

threads which interact with each other. These are related synchronized threads (also referred to as cooperating threads).

• Without synchronization when multiple threads share an object and that object is modified by one or more of the threads, indeterminate results may occur. This is known as a data race or race condition.

• The following example illustrates a race condition. In this example, we simulate a steam boiler and the reading of its pressure. The program starts 10 unsynchronized threads which each read the pressure of the boiler and if it is found to be below the safe limit, the pressure in the boiler is increased by 15psi. If the pressure is found to already be above the safe limit, the pressure is not increased. Looking at the results you can clearly see the problem with this approach.

Page 66: CNT 4714: Enterprise Computing Fall 2014 Programming Multithreaded Applications in Java

CNT 4714: Multi-threaded Applications Page 66 Dr. Mark Llewellyn ©

Class to Simulate a Steam Boiler – Pressure Gauge

Page 67: CNT 4714: Enterprise Computing Fall 2014 Programming Multithreaded Applications in Java

CNT 4714: Multi-threaded Applications Page 67 Dr. Mark Llewellyn ©

Thread Class to Read Steam Boiler Pressure Gauge and Increase the Pressure if Within Range

Page 68: CNT 4714: Enterprise Computing Fall 2014 Programming Multithreaded Applications in Java

CNT 4714: Multi-threaded Applications Page 68 Dr. Mark Llewellyn ©

This is what caused the race condition

to occur.

Output From Execution Illustrating the Race Condition

Page 69: CNT 4714: Enterprise Computing Fall 2014 Programming Multithreaded Applications in Java

CNT 4714: Multi-threaded Applications Page 69 Dr. Mark Llewellyn ©

See. . ., I told you so!

Output From Execution Illustrating No Race Condition

Page 70: CNT 4714: Enterprise Computing Fall 2014 Programming Multithreaded Applications in Java

CNT 4714: Multi-threaded Applications Page 70 Dr. Mark Llewellyn ©

Interesting Note on Race Conditions• You may remember the large North American power blackout that occurred on August

14, 2003. Roughly 50 million people lost electrical power in a region stretching from Michigan through Canada to New York City. It took three days to restore service to some areas.

• See http://en.wikipedia.org/wiki/Northeast_blackout_of_2003 (scroll down to computer failure)

• There were several factors that contributed to the blackout, but the official report highlights the failure of the alarm monitoring software which was written in C++ by GE Energy. The software failure wrongly led operators to believe that all was well, and precluded them from rebalancing the power load before the blackout cascaded out of control.

• Because the consequences of the software failure were so severe, the bug was analyzed exhaustively. The root cause was finally identified by artificially introducing delays in the code (just like we did in the previous example). There were two threads that wrote to a common data structure, and through a coding error, they could both update it simultaneously. It was a classic race condition, and eventually the program “lost the race”, leaving the structure in an inconsistent state. That in turn caused the alarm event handler to spin in an infinite loop, instead of raising the alarm. The largest power failure in the history of the US and Canada was caused by a race condition bug in some threaded C++ code. Java is equally vulnerable to this kind of bug.

Page 71: CNT 4714: Enterprise Computing Fall 2014 Programming Multithreaded Applications in Java

CNT 4714: Multi-threaded Applications Page 71 Dr. Mark Llewellyn ©

The Therac-25 Accidents• Starting in 1976, the Therac-25 treatment system, built by Atomic Energy of

Canada Limited (AECL) and COR MeV of France, was used to fight cancer by providing radiation to a specific part of the body in the hope of destroying tumors.

• See http://en.wikipedia.org/wiki/Therac-25 (See last line of the Problem description.)

• Six known Therac-25 accidents have been documented, all involved massive overdoses (100x normal dose) of radiation and three resulted in the death of the patient, serious long-term injury and disfigurement occurred in the other cases. Patients received an estimated 17,000 to 25,000 rads to very small body areas. By comparison, doses of 1000 rads can be fatal if delivered to the whole body.

• Analysis determined that the primary cause of the overdoses was faulty software. The software was written in assembly language and was developed and tested by the same person. The software included a scheduler and concurrency in its design. When the system was first built, operators complained that it took too long to enter the treatment plan into the computer. As a result, the software was modified to allow operators to quickly enter treatment data by simply pressing the Enter key when an input value did not require changing.

Page 72: CNT 4714: Enterprise Computing Fall 2014 Programming Multithreaded Applications in Java

CNT 4714: Multi-threaded Applications Page 72 Dr. Mark Llewellyn ©

The Therac-25 Accidents (cont.)• This modification created a synchronization error (a race condition developed)

between the code that read the data entered by the operator and the code controlling the machine. As a result, the actions of the machine would lag behind the commands the operator entered. The machine appeared to administer the dose entered by the operator, but it fact had an improper setting that focused radiation at full power to a tiny spot on the body.

• The race condition was subsequently found to occur only when a certain non-typical keystroke sequence was entered (an “X” to select a 25MeV photon followed by “cursor-up” ,”E” to correctly set the 25MeV Electron mode, then “Enter”), since this sequence of keystrokes did not occur very often, the error went unnoticed for a long time.

• AECL was ultimately cited for improperly testing the software, which was only tested on site in hospitals after a machine was assembled in place.

• The designer had reused software from older Therac-6 and Therac-20 models that had hardware interlocks which masked the software defects. Some operators noted that certain situations caused the machines to display MALFUNCTION followed by a number between 1 and 64 on the display screen. However, the user manual did not explain nor even address error codes, so the operators pressed the “P” key (for proceed), to override the warning and proceed with the treatment.

Page 73: CNT 4714: Enterprise Computing Fall 2014 Programming Multithreaded Applications in Java

CNT 4714: Multi-threaded Applications Page 73 Dr. Mark Llewellyn ©

Thread Synchronization• To prevent a race condition, access to the shared object must

be properly synchronized.

– Lost update problem: one thread is in the process of updating the shared value and another thread also attempts to update the value.

– Even worse is when only part of the object is updated by each thread in which case part of the object reflects information from one thread while another part of the same object reflects information from another thread.

• The problem can be solved by giving one thread at a time exclusive access to code that manipulates the shared object. During that time, other threads desiring to manipulate the object must be forced to wait.

Page 74: CNT 4714: Enterprise Computing Fall 2014 Programming Multithreaded Applications in Java

CNT 4714: Multi-threaded Applications Page 74 Dr. Mark Llewellyn ©

Thread Synchronization (cont.)

• When the thread with exclusive access to the object finishes manipulating the object, one of the blocked threads will be allowed to proceed and access the shared object.

– The next selected thread will be based on some protocol. The most common of these is simply FCFS (priority-queue based).

• In this fashion, each thread accessing the shared object excludes all other threads from accessing the object simultaneously. This is the process known as mutual exclusion.

• Mutual exclusion allows the programmer to perform thread synchronization, which coordinates access to shared objects by concurrent threads.

Page 75: CNT 4714: Enterprise Computing Fall 2014 Programming Multithreaded Applications in Java

CNT 4714: Multi-threaded Applications Page 75 Dr. Mark Llewellyn ©

Synchronization Techniques• There have been many different methods used to synchronize

concurrent processes. Some of the more common ones are:

– Test and Set Instructions. All general purpose processors now have this kind of instruction, and it is used to build higher-level synchronization constructs. Test and set does not block, that must be built on top of it.

– p and v semaphores. Introduced by Dijkstra in the 1960’s and was the main synchronization primitive for a long time. Its easy to build semaphores from test and set instructions. Semaphores are low-level and can be hard for programmers to read and debug. For your information the p is short for the Dutch words proberen te verlangen which means to “try to decrement” and the v stands for verhogen which means to increment.

Page 76: CNT 4714: Enterprise Computing Fall 2014 Programming Multithreaded Applications in Java

CNT 4714: Multi-threaded Applications Page 76 Dr. Mark Llewellyn ©

Synchronization Techniques (cont.)

– Read/write Locks. These are also commonly referred to as mutexes (although some people still use the term mutex to refer to a semaphore.) A lock provides a simple ”turnstile”: only one thread at a time can be going through (executing in) a block protected by a lock. Again, it is easy to build a lock from semaphores.

– Monitors. A monitor is a higher-level synchronization construct built out of a lock plus a variable that keeps track of some related condition, such as “the number of unconsumed bytes in the buffer”. It is easy to build monitors from read/write locks. A monitor defines several methods as a part of its protocol. Two of those predefined methods are wait() and notify().

Page 77: CNT 4714: Enterprise Computing Fall 2014 Programming Multithreaded Applications in Java

CNT 4714: Multi-threaded Applications Page 77 Dr. Mark Llewellyn ©

Types of Synchronization• There are two basic types of synchronization between

threads:

1. Mutual exclusion is used to protect certain critical sections of code from being executed simultaneously by two or more threads. (Synchronization without cooperation.)

2. Signal-wait is used when one thread need to wait until another thread has completed some action before continuing. (Synchronization with cooperation.)

• Java includes mechanisms for both types of synchronization.

• All synchronization in Java is built around locks. Every Java object has an associated lock. Using appropriate syntax, you can specify that the lock for an object be locked when a method is invoked. Any further attempts to call a method for the locked object by other threads cause those threads to be blocked until the lock is unlocked.

Page 78: CNT 4714: Enterprise Computing Fall 2014 Programming Multithreaded Applications in Java

CNT 4714: Multi-threaded Applications Page 78 Dr. Mark Llewellyn ©

Thread Synchronization In Java

• Any object can contain an object that implements the Lock interface (package java.util.concurrent.locks).

• A thread calls the Lock’s lock() method to obtain the lock.

• Once a lock has been obtained by one thread the Lock object will not allow another thread to obtain the lock until the thread releases the lock (by invoking the Lock’s unlock() method).

• If there are several threads trying to invoke method lock() on the same Lock object, only one thread may obtain the lock, with all other threads being placed into the wait state.

Page 79: CNT 4714: Enterprise Computing Fall 2014 Programming Multithreaded Applications in Java

CNT 4714: Multi-threaded Applications Page 79 Dr. Mark Llewellyn ©

An Aside on Reentrant Locks• Class ReentrantLock (package java.util.concurrent.locks)

is a basic implementation of the Lock interface.

– The constructor for a ReentrantLock takes a boolean argument that specifies whether the lock has a fairness policy. If this is set to true, the ReentrantLock’s fairness policy states that the longest-waiting thread will acquire the lock when it is available. If set to false, there is no guarantee as to which waiting thread will acquire the lock when it becomes available.

• Using a lock with a fairness policy helps avoid indefinite postponement (starvation) but can also dramatically reduce the overall efficiency of a program. Due to the large decrease in performance, fair locks should be used only in necessary circumstances.

Page 80: CNT 4714: Enterprise Computing Fall 2014 Programming Multithreaded Applications in Java

CNT 4714: Multi-threaded Applications Page 80 Dr. Mark Llewellyn ©

Condition Variables

• If a thread that holds the lock on an object determines that it cannot continue with its task until some condition is satisfied, the thread can wait on a condition variable.

• This removes the thread from contention for the processor by placing it in a wait queue for the condition variable and releases the lock on the object.

• Condition variables must be associated with a Lock and are created by invoking Lock method newCondition, which returns an object that implements the Condition interface.

• To wait on a condition variable, the thread can call the Condition’s await() method (see Life Cycle of a thread in previous set of notes).

Page 81: CNT 4714: Enterprise Computing Fall 2014 Programming Multithreaded Applications in Java

CNT 4714: Multi-threaded Applications Page 81 Dr. Mark Llewellyn ©

Condition Variables (cont.)

• Invoking the await() method, immediately releases the associated Lock and places the thread in the wait state for that Condition. Other threads can then try to obtain the Lock.

• When a runnable thread completes a task and determines that the waiting thread can now continue, the runnable thread can call Condition method signal() to allow a thread in that Condition’s wait queue to return to the runnable state. At this point, the thread that transitioned from the wait state to the runnable state can attempt to reacquire the Lock on the object. Of course there is no guarantee that it will be able to complete its task this time and the cycle may repeat.

Page 82: CNT 4714: Enterprise Computing Fall 2014 Programming Multithreaded Applications in Java

CNT 4714: Multi-threaded Applications Page 82 Dr. Mark Llewellyn ©

Condition Variables (cont.)

• If multiple threads are in a Condition’s wait queue when a signal() is invoked, the default implementation of Condition signals the longest-waiting thread to move to the runnable state.

• If a thread calls Condition method signalAll(), then all of the threads waiting for that condition move to the runnable state and become eligible to reacquire the Lock.

• When a thread is finished with a shared object, it must invoke method unlock() to release the Lock.

Page 83: CNT 4714: Enterprise Computing Fall 2014 Programming Multithreaded Applications in Java

CNT 4714: Multi-threaded Applications Page 83 Dr. Mark Llewellyn ©

Thread States With Synchronization

Thread attemptingaccess

Queue of threads waiting for lock

Already locked by another thread

Running State

Queue of threads waiting for notify()

notify() by another thread

wait() by this threadLock obtained by this thread

Unlock by another thread – one in queue moves to running state

unlock by this thread does not remove it from the running state

Page 84: CNT 4714: Enterprise Computing Fall 2014 Programming Multithreaded Applications in Java

CNT 4714: Multi-threaded Applications Page 84 Dr. Mark Llewellyn ©

Deadlock• Deadlock will occur when a waiting thread (call it thread 1)

cannot proceed because it is waiting (either directly or indirectly) for another thread (call it thread 2) to proceed., while simultaneously thread 2 cannot proceed because it is waiting (either directly or indirectly) for thread 1 to proceed.

• When multiple threads manipulate a shared object using locks, ensure that if one thread invokes await to enter the wait state for a condition variable, a separate thread eventually will invoke method signal to transition the waiting thread on the condition variable back to the runnable state.

– If multiple threads may be waiting on the condition variable, a separate thread can invoke method signalAll as a safeguard to ensure that all of the waiting threads have another opportunity to perform their tasks.

Page 85: CNT 4714: Enterprise Computing Fall 2014 Programming Multithreaded Applications in Java

CNT 4714: Multi-threaded Applications Page 85 Dr. Mark Llewellyn ©

Producer/Consumer Problem Threads Without Synchronization

• In a producer/consumer relationship, the producer portion of an application generates data and stores it in a shared object, and the consumer portion of an application reads data from the shared object.

– Common examples are print spooling, copying data onto CDs, etc.

• In a multithreaded producer/consumer relationship, a producer thread generates data and places it in a shared object called a buffer. A consumer thread reads data from the buffer.

• What we want to consider first is how logic errors can arise if we do not synchronize access among multiple threads manipulating shared data.

Page 86: CNT 4714: Enterprise Computing Fall 2014 Programming Multithreaded Applications in Java

CNT 4714: Multi-threaded Applications Page 86 Dr. Mark Llewellyn ©

Producer/Consumer w/o Synchronization• The following example sets up a producer and consumer thread

utilizing a shared buffer (code is on the webpage). The producer thread generates the integer numbers from 1 to 10, placing the values in the shared buffer. The consumer process reads the values in the buffer and prints the sum of all values consumed.

• Each value the producer thread writes into the buffer should be consumed exactly once by the consumer thread. However, the threads in this example are not synchronized.

– This means that data can be lost if the producer writes new data into the buffer before the consumer has consumed the previous value.

– Similarly, data can be incorrectly duplicated if the consumer thread consumes data again before the producer thread has produced the next value.

Page 87: CNT 4714: Enterprise Computing Fall 2014 Programming Multithreaded Applications in Java

CNT 4714: Multi-threaded Applications Page 87 Dr. Mark Llewellyn ©

Producer/Consumer w/o Synchronization (cont.)

• Since the producer thread will produce the values from 1 to 10, the correct sum that should be 55.

• The consumer process will arrive at this value only if each item produced by the producer thread is consumed exactly once by the consumer thread. No values are missed and none are consumed twice.

• I’ve set it up so that each thread writes to the screen what is being produced and what is being consumed.

• Note: the producer/consumer threads are put to sleep for a random interval between 0 and 3 seconds to emphasize the fact that in multithreaded applications, it is unpredictable when each thread will perform its task and for how long it will perform the task when it has a processor.

Page 88: CNT 4714: Enterprise Computing Fall 2014 Programming Multithreaded Applications in Java

CNT 4714: Multi-threaded Applications Page 88 Dr. Mark Llewellyn ©

// Producer's run method stores the values 1 to 10 in buffer.import java.util.Random;public class Producer implements Runnable{ private static Random generator = new Random(); private Buffer sharedLocation; // reference to shared object

// constructor public Producer( Buffer shared ) { sharedLocation = shared; } // end Producer constructor

// store values from 1 to 10 in sharedLocation public void run() { int sum = 0; for ( int count = 1; count <= 10; count++ ) { try { // sleep 0 to 3 seconds, then place value in Buffer Thread.sleep( generator.nextInt( 3000 ) ); // sleep thread sharedLocation.set( count ); // set value in buffer sum += count; // increment sum of values System.out.printf( "\t%2d\n", sum ); } // end try // if sleeping thread interrupted, print stack trace catch ( InterruptedException exception ) { exception.printStackTrace(); } // end catch } // end for

System.out.printf( "\n%s\n%s\n", "Producer done producing.", "Terminating Producer." ); } // end method run} // end class Producer

Producer Thread Class

Randomly sleep the

thread for up to 3 seconds

Page 89: CNT 4714: Enterprise Computing Fall 2014 Programming Multithreaded Applications in Java

CNT 4714: Multi-threaded Applications Page 89 Dr. Mark Llewellyn ©

// Consumer's run method loops ten times reading a value from buffer.import java.util.Random;public class Consumer implements Runnable { private static Random generator = new Random(); private Buffer sharedLocation; // reference to shared object // constructor public Consumer( Buffer shared ) { sharedLocation = shared; } // end Consumer constructor // read sharedLocation's value four times and sum the values public void run() { int sum = 0; for ( int count = 1; count <= 10; count++ ) { // sleep 0 to 3 seconds, read value from buffer and add to sum try { Thread.sleep( generator.nextInt( 3000 ) ); sum += sharedLocation.get(); System.out.printf( "\t\t\t%2d\n", sum ); } // end try // if sleeping thread interrupted, print stack trace catch ( InterruptedException exception ) { exception.printStackTrace(); } // end catch } // end for System.out.printf( "\n%s %d.\n%s\n", "Consumer read values totaling", sum, "Terminating Consumer." ); } // end method run} // end class Consumer

Consumer Thread Class

Randomly sleep the

thread for up to 3 seconds

Page 90: CNT 4714: Enterprise Computing Fall 2014 Programming Multithreaded Applications in Java

CNT 4714: Multi-threaded Applications Page 90 Dr. Mark Llewellyn ©

Buffer Interface

// Buffer interface specifies methods called by Producer and Consumer.public interface Buffer { public void set( int value ); // place int value into Buffer (WRITE) public int get(); // return int value from Buffer (READ)} // end interface Buffer

// UnsynchronizedBuffer represents a single shared integer.public class UnsynchronizedBuffer implements Buffer { private int buffer = -1; // shared by producer and consumer threads // place value into buffer public void set( int value ) { System.out.printf( "Producer writes\t%2d", value ); buffer = value; } // end method set

// return value from buffer public int get() { System.out.printf( "Consumer reads\t%2d", buffer ); return buffer; } // end method get} // end class UnsynchronizedBuffer

Unsynchronized Buffer Class

Page 91: CNT 4714: Enterprise Computing Fall 2014 Programming Multithreaded Applications in Java

CNT 4714: Multi-threaded Applications Page 91 Dr. Mark Llewellyn ©

// Application shows two threads manipulating an unsynchronized buffer.import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;

public class SharedBufferTest { public static void main( String[] args ){ // create new thread pool with two threads ExecutorService application = Executors.newFixedThreadPool( 2 );

// create UnsynchronizedBuffer to store ints Buffer sharedLocation = new UnsynchronizedBuffer(); System.out.println( " \t\t \tSum \tSum"); System.out.println( "Action\t\tValue\tProduced\tConsumed" ); System.out.println( "------\t\t-----\t--------\t--------\n" );

// try to start producer and consumer giving each of them access to SharedLocationtry {

application.execute( new Producer( sharedLocation ) ); application.execute( new Consumer( sharedLocation ) ); } // end try catch ( Exception exception ) { exception.printStackTrace(); } // end catch

application.shutdown(); // terminate application when threads end } // end main} // end class SharedBufferTest

Producer/ConsumerDriver Class

Page 92: CNT 4714: Enterprise Computing Fall 2014 Programming Multithreaded Applications in Java

CNT 4714: Multi-threaded Applications Page 92 Dr. Mark Llewellyn ©

sharedLocation.set(count)

Producer Side Consumer Side

sharedLocation(Buffer)

set method returns

sum += sharedLocation.get()

get method returns

Unsynchronized Case

running running

Both the producer and consumer threads are always in the running state – never blocked.

Page 93: CNT 4714: Enterprise Computing Fall 2014 Programming Multithreaded Applications in Java

CNT 4714: Multi-threaded Applications Page 93 Dr. Mark Llewellyn ©

The unsynchronizd threads did not produce the same sum. The producer produced values that sum to 55, but the consumer consumed values that sum to 76! Notice that the consumer read the value 10 six times and failed to read the values of several values at all (e.g. 1, 4,5,6,7 and 8).

Page 94: CNT 4714: Enterprise Computing Fall 2014 Programming Multithreaded Applications in Java

CNT 4714: Multi-threaded Applications Page 94 Dr. Mark Llewellyn ©

In this execution, the sum produced by the consumer is closer but still inaccurate because the consumer read the values of 1, 5 and 10 two times and failed to read the values of 2, 4, 6, and 9 at all.

Page 95: CNT 4714: Enterprise Computing Fall 2014 Programming Multithreaded Applications in Java

CNT 4714: Multi-threaded Applications Page 95 Dr. Mark Llewellyn ©

// SynchronizedBuffer synchronizes access to a single shared integer.import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;import java.util.concurrent.locks.Condition;public class SynchronizedBuffer implements Buffer{ // Lock to control synchronization with this buffer private Lock accessLock = new ReentrantLock(); // condition variables to control reading and writing private Condition canWrite = accessLock.newCondition(); private Condition canRead = accessLock.newCondition();

private int buffer = -1; // shared by producer and consumer threads private boolean occupied = false; // whether buffer is occupied // place int value into buffer public void set( int value ) { accessLock.lock(); // lock this object // output thread information and buffer information, then wait try { // while buffer is not empty, place thread in waiting state while ( occupied ) { System.out.println( "Producer tries to write." ); displayState( "Buffer full. Producer waits." ); canWrite.await(); // wait until buffer is empty } // end while

Synchronized Buffer Class

No fairness policy needed since only a single producer thread and single consumer thread

Condition variables on the lock. Condition canWrite contains a queue for threads waiting to write while the buffer is full. If the buffer is full the Producer calls method await on this condition. When the Consumer reads data from a full buffer, it calls method signal on this Condition. Condition canRead contains a queue for threads waiting while the buffer is empty. If the buffer is empty the Consumer calls method await on this Condition. When the Producer writes to the empty buffer, it will call method signal on this Condition.

Acquire lock

Page 96: CNT 4714: Enterprise Computing Fall 2014 Programming Multithreaded Applications in Java

CNT 4714: Multi-threaded Applications Page 96 Dr. Mark Llewellyn ©

buffer = value; // set new buffer value // indicate producer cannot store another value // until consumer retrieves current buffer value occupied = true; displayState( "Producer writes " + buffer ); // signal thread waiting to read from buffer canRead.signal(); } // end try catch ( InterruptedException exception ) { exception.printStackTrace(); } // end catch finally { accessLock.unlock(); // unlock this object } // end finally } // end method set // return value from buffer public int get() { int readValue = 0; // initialize value read from buffer accessLock.lock(); // lock this object // output thread information and buffer information, then wait try { // while no data to read, place thread in waiting state while ( !occupied ) { System.out.println( "Consumer tries to read." ); displayState( "Buffer empty. Consumer waits." ); canRead.await(); // wait until buffer is full } // end while

Signal Consumer thread that a value has been produced and can be read.

Unlock object before exiting method

Acquire lock on the buffer

Consumer must wait until a value has been produced by the Producer. Await signal by Producer

Page 97: CNT 4714: Enterprise Computing Fall 2014 Programming Multithreaded Applications in Java

CNT 4714: Multi-threaded Applications Page 97 Dr. Mark Llewellyn ©

// indicate that producer can store another value // because consumer just retrieved buffer value occupied = false; readValue = buffer; // retrieve value from buffer displayState( "Consumer reads " + readValue ); // signal thread waiting for buffer to be empty canWrite.signal(); } // end try // if waiting thread interrupted, print stack trace catch ( InterruptedException exception ) { exception.printStackTrace(); } // end catch finally { accessLock.unlock(); // unlock this object } // end finally

return readValue; } // end method get // display current operation and buffer state public void displayState( String operation ) { System.out.printf( "%-40s%d\t\t\t\t%b\n", operation, buffer, occupied ); } // end method displayState} // end class SynchronizedBuffer

Signal waiting Producer that the buffer is empty and it can write

Make sure lock is released

Page 98: CNT 4714: Enterprise Computing Fall 2014 Programming Multithreaded Applications in Java

CNT 4714: Multi-threaded Applications Page 98 Dr. Mark Llewellyn ©

// Application shows two threads manipulating a synchronized buffer.import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;public class SharedBufferTest2{ public static void main( String[] args ) { // create new thread pool with two threads ExecutorService application = Executors.newFixedThreadPool( 2 );

// create SynchronizedBuffer to store ints Buffer sharedLocation = new SynchronizedBuffer(); System.out.println("Using Standard Locking"); System.out.printf( "%-40s%s\t\t%s\n%-40s%s\n\n", "Operation", "Buffer Contents", "Occupied", "---------", "---------------\t\t--------" );

try { // try to start producer and consumer application.execute( new Producer( sharedLocation ) ); application.execute( new Consumer( sharedLocation ) ); } // end try catch ( Exception exception ) { exception.printStackTrace(); } // end catch

application.shutdown(); } // end main} // end class SharedBufferTest2

Driver Class For Illustrating Synchronization In Producer/Consumer Problem

Only change between SharedBufferTest for unsynchronized version

Page 99: CNT 4714: Enterprise Computing Fall 2014 Programming Multithreaded Applications in Java

CNT 4714: Multi-threaded Applications Page 99 Dr. Mark Llewellyn ©

accessLock.unlock(); //release lock

Producer Side Consumer Side

sharedLocation(Buffer)

set method returns

readValue= buffer;

get method returns

Synchronized Case

accessLock.lock(); //acquire lock

while (occupied) //buffer not empty

canWrite.await(); block on condition

buffer = value; //perform write

occupied = true; //indicate write

canRead.signal(); //signal thread

canWrite condition queue

no

signal from consumer

lock acquisition queue

accessLock.lock(); //acquire lock

write

while (!occupied) //buffer empty

no

canRead.await(); block

canRead condition queue

occupied = false; //indicate read

signal from producer

canWrite.signal(); //signal thread

accessLock.unlock(); //release lock

released

read

released

wait wait

Page 100: CNT 4714: Enterprise Computing Fall 2014 Programming Multithreaded Applications in Java

CNT 4714: Multi-threaded Applications Page 100 Dr. Mark Llewellyn ©

Producer Thread

Consumer Thread

Running

Running

Blocked

accessLock queue

canWrite condition queue

canRead condition queue

buffer full (occupied)

canWrite signaled

lock request fails

lock released

lock request fails

buffer empty

canRead signaled

State Diagram – Synchronized Version

Page 101: CNT 4714: Enterprise Computing Fall 2014 Programming Multithreaded Applications in Java

CNT 4714: Multi-threaded Applications Page 101 Dr. Mark Llewellyn ©

Both the Producer and Consumer threads produced the same sum – synchronized threads

Page 102: CNT 4714: Enterprise Computing Fall 2014 Programming Multithreaded Applications in Java

CNT 4714: Multi-threaded Applications Page 102 Dr. Mark Llewellyn ©

Both the Producer and Consumer threads produced the same sum – synchronized threads

Page 103: CNT 4714: Enterprise Computing Fall 2014 Programming Multithreaded Applications in Java

CNT 4714: Multi-threaded Applications Page 103 Dr. Mark Llewellyn ©

Monitors and Monitor Locks• Another way to perform synchronization is to use Java’s built-in monitors.

Every object has a monitor. Strictly speaking, the monitor is not allocated unless it is used.

• A monitor allows one thread at a time to execute inside a synchronized statement on the object. This is accomplished by acquiring a lock on the object when the program enters the synchronized statement.

• Where object is the object whose monitor lock will be acquired.

• If there are several synchronized statements attempting to execute on an object at the same time, only one of them may be active on the object at once – all the other threads attempting to enter a synchronized statement on the same object are placed into the blocked state.

synchronized (object){

statements} //end synchronized statement

Page 104: CNT 4714: Enterprise Computing Fall 2014 Programming Multithreaded Applications in Java

CNT 4714: Multi-threaded Applications Page 104 Dr. Mark Llewellyn ©

Mutual Exclusion Over a Block of Statements

• When a synchronized statement finishes executing, the monitor lock on the object is released and the highest priority blocked thread attempting to enter a synchronized statement proceeds.

• Applying mutual exclusion to a block of statements rather than to an entire class or an entire method is handled in much the same manner, by attaching the keyword synchronized before a block of code.

• You must explicitly mention in parentheses the object whose lock must be acquired before the block can be entered.

• The next page illustrates the steam boiler pressure gauge problem using a synchronized statement block to control the threads access to the pressure gauge.

Page 105: CNT 4714: Enterprise Computing Fall 2014 Programming Multithreaded Applications in Java

CNT 4714: Multi-threaded Applications Page 105 Dr. Mark Llewellyn ©

Monitors and Monitor Locks (cont.)

Synchronized block

Synchronized statement requires an Object to lock.

Page 106: CNT 4714: Enterprise Computing Fall 2014 Programming Multithreaded Applications in Java

CNT 4714: Multi-threaded Applications Page 106 Dr. Mark Llewellyn ©

Monitors and Monitor Locks (cont.)

Page 107: CNT 4714: Enterprise Computing Fall 2014 Programming Multithreaded Applications in Java

CNT 4714: Multi-threaded Applications Page 107 Dr. Mark Llewellyn ©

Monitors and Monitor Locks (cont.)

• Java also allows synchronized methods. A synchronized method is equivalent to a synchronized statement enclosing the entire body of a method.

• If a thread obtains the monitor lock on an object and then discovers that it cannot continue with its task until some condition is satisfied, the thread can invoke Object method wait, releasing the monitor lock on the object. This will place the thread in the wait state.

• When a thread executing a synchronized statement completes or satisfies the condition on which another thread may be waiting, it can invoke Object method notify to allow a waiting thread to transition to the blocked state again.

Page 108: CNT 4714: Enterprise Computing Fall 2014 Programming Multithreaded Applications in Java

CNT 4714: Multi-threaded Applications Page 108 Dr. Mark Llewellyn ©

Caution When Using Synchronization

• As with any multi-threaded application, care must be taken when using synchronization to achieve the desired effect and not introduce some serious defect in the application.

• Consider the variation of the pressure gauge example that we’ve been dealing with on the following page. Study the code carefully and try to determine if it will achieve the same effect as the previous version of the code.

• Is it correct? Why or why not?

Page 109: CNT 4714: Enterprise Computing Fall 2014 Programming Multithreaded Applications in Java

CNT 4714: Multi-threaded Applications Page 109 Dr. Mark Llewellyn ©

Does this code correctly synchronize the pressure gauge reading threads?

No! The “this” object is one of the 10 different threads that are created. Each thread will successfully grab its own lock, and there will be no exclusion between the different threads.

Synchronization excludes threads working on the same object; it does not synchronize the same method on different objects!

Page 110: CNT 4714: Enterprise Computing Fall 2014 Programming Multithreaded Applications in Java

CNT 4714: Multi-threaded Applications Page 110 Dr. Mark Llewellyn ©

NO!