290 likes | 429 Views
Java Threading, Mutex and Synchronisation. Lecture 02 COMM86 Concurrent and Distributed Software Systems. Program Threads. A purely sequential (ie. non-concurrent) program contains a single control path that it follows for any given state of its data This path is referred to as a thread.
E N D
Java Threading, Mutex and Synchronisation Lecture 02 COMM86 Concurrent and Distributed Software Systems
Program Threads • A purely sequential (ie. non-concurrent) program contains a single control path that it follows for any given state of its data • This path is referred to as a thread Instruction 3 Instruction 1 Instruction 5 Begin Instruction 2 End Instruction 0 Instruction 4
Program Threads • A concurrent program will consists of any number of concurrently operating threads Instruction 3 Thread 1 Instruction 1 Instruction 5 Begin Instruction 2 End Instruction 0 Instruction 4 Thread 2
Fork and Join • When a single thread becomes a number of additional concurrent threads it is referred to as a fork Thread 1 Instruction 1 Begin Fork Instruction 0 Thread 2
Fork and Join • When any number of concurrently running threads form a single thread it is referred to as a Join Thread 1 Instruction 5 Join End Instruction 4 Thread 2
Synchronisation • At some stage it is possible that a number of concurrently running threads may need to temporarily connect with each other (for example to exchange data) • This requires that the threads synchronise with each other using some mechanism
Java Thread Class • Java provides a class that allows multi-threaded operation of Java programs • This class is called Thread and is part of the java.lang package (so you do not need to import it) • To support this, Java also includes the keyword synchronized to effect mutual exclusion between running threads
Java Thread Mechanism • To enable a Java class to operate as a thread do the following: • Write a class that extends the Thread class • Provide a run( ) method in this class that will form the concurrent operations of the class • Call the start( ) method of the class once it has been instantiated • The thread will terminate when the run( ) operation is completed
An Example • A program to create three independently running threads that each output a set of numbers to the console
Example - Main Program Class public class ThreadExample { public static void main(String argv[]) { ThreadExample theThreadExample = new ThreadExample( ); NumDisplayer[] theNumDisplayers = new NumDisplayer[3]; for(int i = 0; i < 3; i++) { theNumDisplayers[i] = new NumDisplayer(i); // Construct each NumDisplayer theNumDisplayers[i].start( ); // Start each NumDisplayer thread (ie fork) } } }
Example - NumDisplayer Class public class NumDisplayer extends Thread { //Extends the java.lang.Thread class int id; public NumDisplayer(int anId) { id = anId; } public void run( ) { //Method that runs when start( ) method of the this class is called for(int i = 0; i < 4; i++) System.out.println("NumDisplayer [" + id + "] displays " + i); } }
c:> java ThreadExample NumDisplayer [0] displays 0 NumDisplayer [0] displays 1 NumDisplayer [1] displays 0 NumDisplayer [2] displays 0 NumDisplayer [0] displays 2 NumDisplayer [1] displays 1 NumDisplayer [2] displays 1 NumDisplayer [0] displays 3 NumDisplayer [1] displays 2 NumDisplayer [2] displays 2 NumDisplayer [1] displays 3 NumDisplayer [2] displays 3 c:> Note how the order in which each thread displays to the console is interleaved Example - Typical Output in MSDOS
Synchronized Keyword • Any Java class method can be declared as synchronized. • Once synchronized, only one thread may enter that method at anytime. Other threads wishing to do so block until the orignal thread has completed running the synchronized method. • Hence you can use a synchronized method to ensure mutual exclusive access to a class’s data
Use of Synchronized • To make a method synchronized, use the synchronized keyword as a modifier for the method, eg. public synchronized void setData(int newData) { data = newData; }This would allow a single thread to update the data attribute of the class containing the setData() method at any given moment
Example 2 using synchronized • Let us adapt the previous example so the NumDisplayer objects take their value to display from another thread based upon a class called NumCounter
Example 2 - Main Program Class public class ThreadExample2 { public static void main(String argv[]) { ThreadExample2 theThreadExample = new ThreadExample2( ); NumCounter theNumCounter = new NumCounter( ); // Construct the NumCounter theNumCounter.start( ); // Start the NumCounter NumDisplayer2[] theNumDisplayers = new NumDisplayer2[3]; for(int i = 0; i < 3; i++) { theNumDisplayers[i] = new NumDisplayer2(i, theNumCounter); // Construct each NumDisplayer theNumDisplayers[i].start( ); // Start each NumDisplayer } } }
Example 2 - NumCounter Class public class NumCounter extends Thread { int counter; public NumCounter( ) { counter = 0; } public synchronized int getNextNum( ) { int currentNum = counter; updateCounter( ); return currentNum; } public synchronized void updateCounter( ) { counter++; } public void run( ) { while(true) { //Go on and on ... try { Thread.sleep(100); // Let other threads operate, see later } catch(InterruptedException ie) { // Required because this exception is thrown by Thread.sleep( ) } } } }
Example – NumDisplayer2 Class public class NumDisplayer2 extends Thread { int id; NumCounter theNumCounter; // Reference to the NumCounter public NumDisplayer2(int anId, NumCounter aNumCounter) { id = anId; theNumCounter = aNumCounter; } public void run( ) { for(int i = 0; i < 4; i++) System.out.println("NumDisplayer [" + id + "] displays " + theNumCounter.getNextNum( )); } }
c:> java ThreadExample2 NumDisplayer [0] displays 0 NumDisplayer [2] displays 1 NumDisplayer [1] displays 2 NumDisplayer [0] displays 3 NumDisplayer [1] displays 4 NumDisplayer [2] displays 5 NumDisplayer [0] displays 6 NumDisplayer [0] displays 7 NumDisplayer [2] displays 8 NumDisplayer [1] displays 9 NumDisplayer [1] displays 10 NumDisplayer [2] displays 11 c:> Note how the order in which each thread displays to the console is still interleaved and that any thread can output any of the possible numbers. This is because we have no control over the sequence that the threads operate in. Example - Typical Output in MSDOS
Thread Scheduling • Notice that the previous example ensures mutual exclusion, but what about scheduling? • Java has a pre-emptive, priority-based thread scheduler • This means that if a higher priority thread needs the CPU, a currently running lower priority thread will be interrupted
Fairness • If all threads are of equal priority, then the currently running thread will not be interrupted and get exclusive use of the CPU. • Thus we get an unfair scheduling of equal (or lesser) priority threads • Because of this, a thread must periodically relinquish its use of the CPU in consideration of other threads
Thread.sleep( ) • To achieve this fairness in your Java programs, use the static method Thread.sleep( ) to temporarily halt any long running thread. This allows other threads access to the CPU. • The method takes an integer value parameter that represents the time (in milliseconds) the thread will halt. 100 is a good value for this. • Note: the Thread.sleep( ) method throws an InterruptedException exception, so this must be caught
Thread.sleep( ) Example • The NumCounter class used previously introduced a Thread.sleep( ) method call within its run( ) method.(See the previous ThreadExample2 slides)
Runnable Interface • The previous examples have used the idea of extension to enable a class to run as a thread. This is problematic if the class must also extend another class (such as JFrame) • To overcome this, you can make the class implement the Runnable interface, which allows the class to be considered a thread
Runnable Interface • The Runnable Interface contains a single run( ) method that needs to be implemented (as per any thread) • Once a class implements the Runnable interface, you can construct a thread for this class by passing its class reference to the Thread class constructor • Once the thread is started, the run( ) method of the class will be called
Runnable Interface Example For example public class ThreadExample3 implements Runnable { Thread myThread; // Reference to the thread this object will run upon public ThreadExample3( ) { myThread = new Thread(this); // Construct the thread myThread.start( ); // Start the thread, ie call the run( ) method of the ThreadExample3 class } public static void main(String argv[]) { ThreadExample3 theThreadExample = new ThreadExample3; } public void run( ) { while(true) { // do something, and use Thread.sleep( ) to show consideration to other threads } } }
Thread Death • Threads stop running under three circumstances:1. The run( ) method completes2. You call the stop( ) method of the thread (note this is now a deprecated method so don’t use it!)3. The whole process within which the thread is running is terminated (i.e. when the Java VM completes) • Since we have to control the lifespan of a thread through the run( ) method, it is prudent to make this method come under direct control also by using a completion flag
Completion Flag • Use a boolean variable to indicate whether the thread has completed or not. Use this as the condition for the while statement in the run( ) method, eg.boolean completed = false;public void run( ) { while(!completed) { …. }}
Is This All? • No. The subject of Java threads is large and impossible to do it justice in a single session. There will be more. • You can find out more in the Java Tutorial and in most of the Java texts • For a near complete treatment of the subject, consult“Java Threads”, Scott Oaks & Henry Wong, O’Reilly, 1997“Concurrent Programming in Java”, Doug Lea, Addison Wesley, 2000