copyright 2003 mudra services1 threads multitasking many processes running on the same machine share...
TRANSCRIPT
Copyright 2003 Mudra Services
1
Threads
Multitasking Many processes running on the same machine
share the processor Each process can have multiple threads
of control In java the process is the JVM (Java Virtual
Machine) Examples of threads
Main Thread Garbage collection thread Swing Event dispatching thread
Copyright 2003 Mudra Services
2
Threads – Process Vs Thread
Process Heavy weight The operating system has to do a lot more to
create a process Expensive to create a process
Thread Light weight (also called Light Weight
Process-LWP) Relatively inexpensive Has it’s own stack but shares the heap with
other threads in the same process
Copyright 2003 Mudra Services
3
Thread – Scenarios - Why Threads?
Any operation that takes a long time to complete needs a thread.
Suppose a user is editing a file. Let’s say the user wants to find all files which contain a particular keyword. The FIND operation can be put in a separate thread so that the user can continue to edit the file.
Copyright 2003 Mudra Services
4
Thread – Scenarios - Why Threads?
Any work which needs to be done in the background needs a thread
A Garbage collection thread collects all unused objects silently
In networked programs, an application might PING a server periodically to check if the server is running. This would need a separate thread.
Copyright 2003 Mudra Services
5
Thread – Scenarios - Why Threads?
To support many users in a server environment, multiple threads are a must.
All application servers support a thread per user paradigm. All user requests are supported on a
separate thread.
Copyright 2003 Mudra Services
6
Thread - Creation
Thread class Associated with a thread of control
Extending from the Thread class Thread class extends the Object class
public class FindThread extends Thread { ….. public void run() { // block of code which needs to be put // in a separate thread }} // end class FindThread
Copyright 2003 Mudra Services
7
Thread - Creation
Starting the thread FindThread findThr = new FindThread();
findThr.start();
start() method will call the run() method of the Thread class on a different thread of control.
Once the run() method ends, the thread has completed and cannot be reused.
Copyright 2003 Mudra Services
8
Thread - Creation
package threads;
public class SimpleThread extends Thread {
public void run() { // print 0 to 99 for (int j=0;j<100;j++) { System.out.println("SimpleThread :: " + j); } } // end run()
Copyright 2003 Mudra Services
9
Thread - Creation
public static void main(String[] args) { // This is the main thread SimpleThread simpleThr = new SimpleThread(); simpleThr.start();
// print 0 to 99 for (int j=0;j<100;j++) { System.out.println("main() :: " + j); } } // end main()
} // end SimpleThread
Copyright 2003 Mudra Services
10
Thread - Creation
Graphical run of the programMain Thread
Simple Thread
simpleThr.start()
Copyright 2003 Mudra Services
11
Thread - Creation
Part of the output
main() :: 34main() :: 35main() :: 36main() :: 37SimpleThread :: 0main() :: 38SimpleThread :: 1SimpleThread :: 2SimpleThread :: 3main() :: 39SimpleThread :: 5
Copyright 2003 Mudra Services
12
Thread - Creation
Implementing the Runnable interface
public class Find extends SomeClass implements Runnable {
public void run() { // block of code which needs to be put // in a separate thread }
} // end class Find
Copyright 2003 Mudra Services
13
Thread - Creation
Starting the thread Find findRunner = new Find(…); Thread findThr = new Thread(findRunner); findThr.start();
start() method will call the run() method of the Runnable interface on a different thread of control.
Once the run() method ends, the thread has completed and cannot be reused.
Copyright 2003 Mudra Services
14
Thread - Creation
package threads;
public class SimpleRunner implements Runnable {
public void run() { // print 0 to 4 for (int j=0;j<100;j++) { System.out.println("SimpleThread :: " + j); } } // end run()
Copyright 2003 Mudra Services
15
Thread - Creation
public static void main(String[] args) { // This is the main thread SimpleRunner simpleRunner = new SimpleRunner(); Thread simpleThr = new Thread(simpleRunner); simpleThr.start();
// print 0 to 4 for (int j=0;j<100;j++) { System.out.println("main() :: " + j); } } // end main()
} // end SimpleRunner
Copyright 2003 Mudra Services
16
Thread - Methods
Thread.currentThread() Gets the Thread object associated with the
current thread of control.
getName()/setName() Get or set the name associated with the
thread. Always provide a name of the thread when
created. Good for debugging. With every debug statement the name of the
thread must be entered
Copyright 2003 Mudra Services
17
Thread - Methods
start() Starts a new thread of control Throws IllegalThreadStateException if the
thread is already alive
isAlive() Returns TRUE if the thread has started but
not ended
Copyright 2003 Mudra Services
18
Thread - Methods
Thread.sleep(time) Sleeps for ‘time’ millisecs Can throw an InterruptedException if
some other threads interrupts this thread
Copyright 2003 Mudra Services
19
Threads – Stack and Heap Revisited
Process [JVM]
Thread 1 Thread 2 Thread 3 Heap
o
o
ostack stack stack
Copyright 2003 Mudra Services
20
Threads – Stack and Heap Revisited
Every thread has a stack. The process Heap is shared by all the
threads in the process. Objects in the process heap can be
accessed by multiple threads in the system
Since the threads can access the same object at the same time, this can lead to corruption of object.
Synchronization Thread Safety
Copyright 2003 Mudra Services
21
Threads – Synchronization
A unique ID generator
package threads;public class IDGenerator { private int ID = 0;
public int getID() { ID = ID + 1; // Not Atomic return(ID); }} // end IDGenerator
- Read(ID)- Add(ID,1)- Write(ID)
Copyright 2003 Mudra Services
22
Threads – Synchronization
package threads;public class SimpleRunner implements Runnable { private IDGenerator idGen;
public SimpleRunner(IDGenerator idGen) { this.idGen = idGen; }
public void run() { // print 0 to 99 for (int j=0;j<100;j++) { System.out.println("SimpleThread :: " + idGen.getID()); } } // end run()
Generate 100 ids
Copyright 2003 Mudra Services
23
Threads – Synchronization
public static void main(String[] args) { // create the ID generator IDGenerator idGen = new IDGenerator();
// This is the main thread SimpleRunner simpleRunner = new SimpleRunner(idGen); Thread simpleThr = new Thread(simpleRunner); simpleThr.start();
// print 0 to 99 for (int j=0;j<100;j++) { System.out.println("main() :: " + idGen.getID()); } } // end main()}
Generate 100 ids
Copyright 2003 Mudra Services
24
Threads – Synchronization
Synchronize the getID() method This will ensure that only one thread will
enter the method at one time.
public synchronized int getID() { ID = ID + 1; return(ID); }
Copyright 2003 Mudra Services
25
Threads – Synchronization
Synchronized keyword ensures that only one thread is allowed inside the method at a time.
Other threads which call the same method will block.
Every object has a lock associated with it. When synchronized method is called, the
JVM locks the object.
Copyright 2003 Mudra Services
26
Threads – Synchronization
Synchronize on the methodpublic synchronized int setPoint(int x,int y) { // LOCK
OBTAINED this.x = x; this.y = y;} // LOCK RELEASED
Synchronize statement blockpublic int setPoint(int x,int y) { synchronized(this) { // LOCK OBTAINED this.x = x; this.y = y; } // LOCK RELEASED}
Copyright 2003 Mudra Services
27
Threads – Synchronization
Synchronize on an objectpublic int setPoint(int x,int y) { …. synchronized(obj) { // obj LOCK OBTAINED // statements } // obj LOCK RELEASED …..}
Synchronizing on an object – means we are obtaining the lock for that object.
Copyright 2003 Mudra Services
28
Threads – Synchronization
package threads;public class NameThread extends Thread { private String first = null; private String last = null;
public NameThread() { }
public void run() { String name = "namethread"; for(int j=10;j<20;j+=2) { setNames(name + j, name + (j+1)); } }
Copyright 2003 Mudra Services
29
Threads – Synchronization
// Set the first and last names. PROBLEM CHILD !!! public void setNames(String f,String l) { first = f;
// yield the processor to some other thread. // Just to reproduce the problem.
Thread.currentThread().yield();
last = l;
// print the first and last names System.out.println(first + " " + last); }
Can be a very usefulfor debugging purposes
Copyright 2003 Mudra Services
30
Threads – Synchronization
public static void main(String[] args) { NameThread nameThread1 = new NameThread(); nameThread1.start();
String name = "main"; for(int j=0;j<10;j+=2) { nameThread1.setNames(name + j, name + (j+1)); } }}
Copyright 2003 Mudra Services
31
Threads – Synchronization
OUTPUT
namethread10 main1main2 namethread11namethread12 main3main4 namethread13namethread14 main5main6 namethread15namethread16 main7main8 namethread17namethread18 main9namethread18 namethread19
Copyright 2003 Mudra Services
32
Threads – Synchronization
Again, solution is to make the setNames() method “synchronized”
OUTPUTmain0 main1namethread10 namethread11main2 main3namethread12 namethread13main4 main5namethread14 namethread15main6 main7namethread16 namethread17main8 main9namethread18 namethread19
Copyright 2003 Mudra Services
33
Threads – Synchronization
Assume that a class contains methods m1, m2, m3 – out of which m1 and m2 are synchronized and m3 is not. If two threads simultaneously can m1
one thread will block. If one thread calls m1, other calls m2
one thread will block If one thread calls m1 and the other m3
both threads will execute simultaneously.
Copyright 2003 Mudra Services
34
Threads – Synchronization
Each class is associated with a Class Level lock
Synchronized keyword used for static methods lock-unlock the class level LOCK.
Synchronized Method public synchronized static int getID() {
ID = ID + 1; return(ID); }
Copyright 2003 Mudra Services
35
Threads – Synchronization
Synchronized blocksynchronized (className.class) {
// statements}
public static int getID() { synchronized(IDGenerator.class) {
ID = ID + 1; return(ID);}
}
Copyright 2003 Mudra Services
36
Exercise 1
Write a program to spawn 10 threads simultaneously each printing integers from 1 to 100.
Copyright 2003 Mudra Services
37
Exercise 2
Create a class called MTStack (Multi Threaded Stack) which has the following methods
public void push(Object o) throws MTStackException Throws exception when the stack limit is reached
public Object pop() throws MTStackException Throws exception when the stack is empty
public Object peek() throws MTStackException Throws exception when the stack is empty
How are you ensuring that the class is thread safe?
Copyright 2003 Mudra Services
38
Exercise 2
Define the data members as an array of objects A user of the stack will use as follows
MTStack mtstack = new MTStack(3); try { mtstack.push("1"); mtstack.push("2"); mtstack.push("3"); mtstack.pop(); mtstack.pop(); mtstack.pop(); } catch (MTStackException exp) { System.out.println(exp.getMessage()); }
Copyright 2003 Mudra Services
39
Exercise 2
Access the MTStack object in a multi-threaded environment and see that the object is not corrupted.
Copyright 2003 Mudra Services
40
Threads – Java Memory Model
Main Memory
Working Area Working Area
Thread-1 Thread-2
Copyright 2003 Mudra Services
41
Threads – Java Memory Model
The model defines an abstract relationship between the main memory and the threads
Each thread is defined to have a working area
Most rules are based on when values can transferred between the main memory and the per thread working area
Rules Atomicity Visibility Ordering
Copyright 2003 Mudra Services
42
Threads – Java Memory Model
Atomicity Atomicity guarantees the fact that when a
non-long/double field is used in an expression – you either obtain the initial value OR some value written by some thread
No jumble of bits is obtained Accesses/updates to any field other than
long and double are atomicint x = 4;x = 5; // x is either 4 or 5 (not a jumble of bits)
Copyright 2003 Mudra Services
43
Threads – Java Memory Model
Examples of non–atomic expressions// integer expressionsx = x + 1;
x++;
// long expression
long l = 5;l = 10;
Atomicity does not guarantee that a value written by a thread will be seen by another thread
Copyright 2003 Mudra Services
44
Threads – Java Memory Model
Visibility
Acquiring the lock reloads all the field values which can be accessed from the block
Freeing a lock flushes all writes from the working memory to the heap
If a field is declared volatile, any value written to it is flushed into main memory
When a thread terminates all written variables are flushed to main memory.
Copyright 2003 Mudra Services
45
Threads – Java Memory Model
Two reasons for the synchronized keyword To prevent the object from going into
inconsistent state. Means for mutual exclusion (mutex)
Effects of changes made by other threads are seen
Changes made by a thread without the synchronized block may never be seen by another thread
Copyright 2003 Mudra Services
46
Threads – Java Memory Model
package threads;
public class IDGenerator { private int ID = 0;
public int getID() { ID = ID + 1; return(ID); }}
Copyright 2003 Mudra Services
47
Threads – Java Memory Model
What is the flaw in the example? How will you remove the flaw? Can you use the volatile keyword?
Copyright 2003 Mudra Services
48
Threads – Java Memory Model
public class FindThread extends Thread { private boolean stop = false; public void run() { boolean done = false; while(!stop && !done) { // do the find request in the loop } } public void requestStop() { stop = true; }} // end Find Thread
Copyright 2003 Mudra Services
49
Threads – Java Memory Model
What is the problem with the previous example?
How are you going to resolve this? Can you use the volatile keyword for
stop data member?
Copyright 2003 Mudra Services
50
Threads – Interrupting Threads
interrupt() When one thread is running, another thread
can interrupt it by calling the method It simply sets the interrupted flag for the
thread
isInterrupted() A thread can check if it was interrupted by
another thread Returns true if it was interrupted The call does not clear the interrupted flag
Copyright 2003 Mudra Services
51
Threads – Interrupting Threads
Thread.interrupted() Static method which acts on the current thread Returns true if the thread was interrupted Resets the flag after the call
A thread can be interrupted to tell it to gracefully shutdown
But it can also be used for other purposes
Copyright 2003 Mudra Services
52
Threads – Interrupting Threads
package threads;public class InterruptExample {
public static void main(String[] args) {
System.out.println("Point X: Thread.interrupted() = " + Thread.interrupted()); Thread.currentThread().interrupt(); System.out.println("Point Y: Thread.interrupted() = " + Thread.interrupted()); System.out.println("Point Z: Thread.interrupted() = " + Thread.interrupted()); }}
Copyright 2003 Mudra Services
53
Threads – Interrupting Threads
Output ::
Point X: isInterrupted() = falsePoint Y: isInterrupted() = truePoint Z: isInterrupted() = false
Copyright 2003 Mudra Services
54
Threads – Interrupting Threads
package threads;public class InterruptExample {
public static void main(String[] args) { Thread current = Thread.currentThread(); System.out.println("Point X: isInterrupted() = " + current.isInterrupted()); Thread.currentThread().interrupt(); System.out.println("Point Y: isInterrupted() = " + current.isInterrupted()); System.out.println("Point Z: isInterrupted() = " + current.isInterrupted()); }}
Copyright 2003 Mudra Services
55
Threads – Interrupting Threads
Output ::
Point X: isInterrupted() = falsePoint Y: isInterrupted() = truePoint Z: isInterrupted() = true
Copyright 2003 Mudra Services
56
Threads – Interrupting Threads
Sleeping Threads A Thread can be sleeping using
Thread.sleep() or Object.wait() or Thread.join()
On interruption, a sleeping thread will throw an InterruptedException
If an interrupt is pending before the sleep, it immediately throws an InterruptedException
The interrupted flag is cleared when the exception is caught
Copyright 2003 Mudra Services
57
Threads – Interrupting Threads
try { Thread.sleep(60*60*1000); // Thread is sleeping}catch (InterruptedException exp) { // The thread was interrupted. In most cases this // might mean that the thread was told to die
gracefully}
Copyright 2003 Mudra Services
58
Threads – Stopping a Thread
stop() Stops the thread abruptly Causes a ThreadDeath error to be thrown Finally terminates the thread of control Deprecated from JDK 1.2 (but not in 1.0 and
1.1) It can lead to corrupted data since there is
no way to cleanup According to javadocs, it can also lead to
deadlock conditions
Copyright 2003 Mudra Services
59
Threads – suspend
suspend() Temporarily pause the thread Deprecated from JDK1.2 (but not in 1.0 and 1.1) Can suspend in the middle of a synchronized
block Can lead to deadlocks
resume() Resumes a suspended thread Deprecated from JDK1.2 (but not in 1.0 and 1.1)
since suspend() is deprectaed
Copyright 2003 Mudra Services
60
Threads – Stopping/Canceling a Thread
Do not use the stop() method for canceling the thread
Why does a thread needs to be stopped? A direct GUI request from the user Programs which start the threads must stop
them before they die When a thread starts giving errors
Typically the threads that we need to stop do work periodically and/or in a loop
Copyright 2003 Mudra Services
61
Threads – Stopping/Canceling a Thread
interrupt() can be used effectively to cancel any thread Thread.sleep(), Thread.join(), Object.wait()
responds to interrupt by throwing the InterruptedException
Other places should check for the interrupted status periodically and make sure that the thread terminates.
Responsiveness of the thread will depend on the number of checks
Copyright 2003 Mudra Services
62
Threads – Stopping/Canceling a Thread
package threads;
public class FindThread extends Thread { private String directory; private String keyword; private boolean stop;
public FindThread(String directory,String keyword) { this.directory = directory; this.keyword = keyword; }
Copyright 2003 Mudra Services
63
Threads – Stopping/Canceling a Thread
public void run() { File nextFile = null; boolean done = false; while(!getStop() && !done) { nextFile = <determine next file>; try { checkIfKeywordInFile(nextFile); } catch (InterruptedException exp) {} } }
public synchronized void die() { stop = true;
this.interrupt(); }
Copyright 2003 Mudra Services
64
Threads – Stopping/Canceling a Thread
synchronized boolean getStop() { return(stop); }
public void checkIfKeywordInFile(File file) throws InterruptedException { while (!done) { // check if the thread was interrupted. Highly responsive if (Thread.currentThread().isInterrupted()) { throw new InterruptedException(); } <check if keyword in file> } } } // end FindThread
Copyright 2003 Mudra Services
65
Threads – Stopping/Canceling a Thread
// Create the FindThread and start it. FindThread finder = new FindThread(<directory>,<keyword>);finder.start();…..// Terminate the find thread of controlfinder.die();
Example is a very responsive find thread. Check is made after every line read Performance impact Can check after every 100 lines or every
file.
Copyright 2003 Mudra Services
66
Threads – Stopping/Canceling a Thread
A pinging Thread
package threads;public class MachinePinger extends Thread {
private String machine; private boolean stop = false;
public MachinePinger(String machine) { this.machine = machine; }
Copyright 2003 Mudra Services
67
Threads – Stopping/Canceling a Thread
public void run() { while(!getStop()) { try { // code to ping here ... doPing();
Thread.sleep(10*60*1000); } catch (InterruptedException exp) { // do nothing } } // do some cleanup before going down doCleanup(); }
Copyright 2003 Mudra Services
68
Threads – Stopping/Canceling a Thread
synchronized void die() { stop = true; this.interrupt(); }
synchronized boolean getStop() { return(stop); }
} // end MachinePinger
Copyright 2003 Mudra Services
69
Threads – Stopping/Canceling a Thread
Two situations when the thread is not able to check on the interrupted status When the thread is blocked on a
synchronized call. The thread is trying to get a lock.
When the thread is doing IO InterruptedException is not thrown in the
above two cases
Copyright 2003 Mudra Services
70
Exercise 3
Write a program called FileMonitor which monitors a particular file in the system. The program should spawn a thread which will periodically (every 30 secs) monitor the file. If the file is available, it should print “File available”. It can also accept input (quit) from the standard input to quit the program. File name can be taken from the command line.
If the file is removed, the thread should print out a message “File removed” and terminate the thread.
When the program is told to quit, it should stop the thread and the FileMonitor should terminate
Copyright 2003 Mudra Services
71
Exercise 3
prompt>java FileMonitor temp.txtEnter quit to exitFile availableFile available….quitprompt>
Copyright 2003 Mudra Services
72
Threads - Singleton
Only one object for the class can be instantiated
Typically used so that multiple instances of a class need not be created when one is sufficient
Private constructor Static method to retrieve the only object A configuration file for an application
might be read using a singleton.
Copyright 2003 Mudra Services
73
Threads - Singleton
public class X { private static X xRef; // other data members here private X() { // initialize X } public static X getInstance() { if (xRef == null) { xRef = new X(); } return(xRef); } // other methods here}
Thread unsafe How do we make
this MT Safe?
Two threads can create Xat the same time.
Copyright 2003 Mudra Services
74
Threads - Singleton
public class X { private static X xRef; // other data members here private X() { // initialize X } public synchronized static X getInstance() { if (xRef == null) { xRef = new X(); } return(xRef); } // other methods here}
Only one thread can enterat a time. Thus, this isThread-safe
Copyright 2003 Mudra Services
75
Threads – Double Checked Locking
public static X getInstance() {
if (xRef == null) { synchronized(X.class) { if (xRef == null) { xRef = new X(); } } } return(xRef); }
Problems with the above?
Intention here is to notincur the penalty of synchronization oncethe object is created.
Copyright 2003 Mudra Services
76
Threads – Double Checked Locking
Clever but broken xRef is being accessed without the
synchronized keyword The xRef can be assigned before the
object is fully constructed (depending on the JVM)
Copyright 2003 Mudra Services
77
Threads - Swing
Swing is single threaded All actions are executed on the SWING
event dispatching thread Choice of speed over safety Be very careful when making changes
to Swing components outside the event thread
Copyright 2003 Mudra Services
78
Threads - SwingSWING Event Thread
Queue
Message
This thread will executeall messages in the queue.In effect, all updates to SWING interface happens from this thread.
Copyright 2003 Mudra Services
79
Threads - Swing
package swingexample;
import javax.swing.*;import java.awt.*;import java.awt.event.*;
public class SwingExample extends JFrame implements ActionListener { private JLabel textLabel; private JButton clickButton;
public SwingExample() { this.getContentPane().setLayout(new
FlowLayout(FlowLayout.CENTER)); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Copyright 2003 Mudra Services
80
Threads - Swing
// create componets textLabel = new JLabel("Click to submit "); clickButton = new JButton("Submit",new
ImageIcon("AppletIcon.gif")); clickButton.setMnemonic('S');
// add a listener clickButton.addActionListener(this);
// add components to container this.getContentPane().add(textLabel); this.getContentPane().add(clickButton); }
Copyright 2003 Mudra Services
81
Threads - Swingpublic static void main(String[] s) { SwingExample example = new SwingExample(); example.setTitle("A Sample Frame"); // show the container on the screen example.pack(); example.setVisible(true); } // end main
public void actionPerformed(ActionEvent e) { if (textLabel.getText().startsWith("Click")) { textLabel.setText("Changed Text"); textLabel.setForeground(Color.blue); } else { textLabel.setText("Click to submit "); textLabel.setForeground(Color.black); } } // end actionperformed}
Executed in theEvent dispatchingthread.
Copyright 2003 Mudra Services
82
Threads - Swing
The actionPerformed() is called from the event thread
A time consuming action can tie the GUI up
Actions which go across the network can take time
Threads can be used effectively to handle the situation
If the action can take significant time, put that action in a separate thread
Copyright 2003 Mudra Services
83
Threads - Swing
A find operation might take time. So …. It is put on a separate thread from
inside actionPerformed method call
public void actionPerformed(ActionEvent e) { FindThread finder = new FindThread(...); finder.start(); ....}
Notice that a new thread is spawned from inside theactionPerformed method
Copyright 2003 Mudra Services
84
Threads - Swing
Swing Event Thread
Find Thread
Copyright 2003 Mudra Services
85
Threads - Swing
How would the find thread modify the GUI?
Use SwingUtilities.invokeAndWait(..) Use SwingUtilities.invokeLater(..) The above methods queue the requests
in the event queue. The event thread handles the requests
and everything is fine
Copyright 2003 Mudra Services
86
Threads – invokeAndWait()
The event thread calls the run() method Waits till the run() method is complete Note that no thread is started here
Runnable updateProgress = new Runnable() { public void run() { // handle progress update } } SwingUtilities.invokeAndWait(updateProgress);
Copyright 2003 Mudra Services
87
Threads – invokeLater()
The event thread calls the run() method Returns immediately No thread is started here
Runnable updateProgress = new Runnable() { public void run() { // handle progress update } } SwingUtilities.invokeLater(updateProgress);
Copyright 2003 Mudra Services
88
Threads – Example
A search screen A token is entered in the text field and
search button clicked.
Copyright 2003 Mudra Services
89
Threads – Example
package threads;import java.awt.*;import javax.swing.*;import java.awt.event.*;public class SearchExample extends JFrame implements
ActionListener { private JTextField field; private JButton searchB; private JButton cancelB; private JLabel label; private SearchThread thread;
public SearchExample() { this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); field = new JTextField();
Copyright 2003 Mudra Services
90
Threads – Example
JPanel spanel = new JPanel(); searchB = new JButton("Search"); cancelB = new JButton("Cancel"); searchB.addActionListener(this); cancelB.addActionListener(this); cancelB.setEnabled(false); label = new JLabel("Not Found"); spanel.add(searchB); spanel.add(cancelB); spanel.add(label);
this.getContentPane().add("North",field); this.getContentPane().add("South",spanel); }
Copyright 2003 Mudra Services
91
Threads – Example
public static void main(String[] args) { SearchExample sexample = new SearchExample(); sexample.pack(); sexample.setVisible(true); }
public void actionPerformed(ActionEvent e) { Object source = e.getSource(); if (source == searchB) { // start the search thread thread = new SearchThread(field.getText(),label); thread.start();
searchB.setEnabled(false); cancelB.setEnabled(true); }
A separate Search thread iscreated to do the search.
Copyright 2003 Mudra Services
92
Threads – Example
else if (source == cancelB) { // stop the thread if (thread != null) { thread.die(); thread = null;
searchB.setEnabled(true); cancelB.setEnabled(false); } } }
} // end SearchExample
We stop the thread whenuser clicks on cancel.
Copyright 2003 Mudra Services
93
Threads - Swing
package threads;import javax.swing.*;
public class SearchThread extends Thread { private String text; private JLabel label; private boolean stop = false;
public SearchThread(String text,JLabel label) { this.text = text; this.label = label; }
Copyright 2003 Mudra Services
94
Threads - Swing
// Algorithm for FIND is not specified. But it takes a min to complete public void run() { for(int j=0; (j < 6) && !getStop(); j++) { // ALGORITH FOR FIND // wait for 10 secs try { Thread.sleep(10*1000); } catch (InterruptedException e) { } } // end for
Copyright 2003 Mudra Services
95
Threads - Swing
// create runnable and invoke it Runnable labelSetter = new Runnable() { public void run() { if (getStop()) { label.setText("Cancelled"); } else { label.setText("Found"); } } };
SwingUtilities.invokeLater(labelSetter); }
Update the GUI from theSearch thread. Needed forthread safety.
Copyright 2003 Mudra Services
96
Threads - Swing
public synchronized void die() { this.stop = true; this.interrupt(); }
public synchronized boolean getStop() { return(stop); }
} // end search thread
Why do we need to send an interrupt?
Copyright 2003 Mudra Services
97
Threads - Swing
Note the use of invokeLater Can easily add progress bar indicator Note the usage of synchronized
keyword for stopping the thread
How does a method know if it is being executed by the event dispatching thread?
boolean value = SwingUtilities.isEventDispatchingThread()
Copyright 2003 Mudra Services
98
Threads – Inter Thread Communication
Queue example for waiting for some messages Swing Event Queue
Busy/Wait scheme Sleep for arbitrary time and check for the
variable Wait can be long Processor time is used unnecessarily Not efficient
Copyright 2003 Mudra Services
99
Threads – Busy/Wait Scheme
Example of a code waiting for the value to change to the desired value before taking action
while(getValue() != desiredValue) { Thread.sleep(500);}
Wait/Notify/NotifyAll Scheme Better way for inter thread communication
Copyright 2003 Mudra Services
100
Threads – Wait/Notify
wait() sleeps till it is notified by some other thread to wake up
wait() can be called only after obtaining a lock
wait() releases the lock temporarily try { synchronized (obj) { obj.wait(); } } catch (InterruptedException exp) { // handle interrupted exception }
Copyright 2003 Mudra Services
101
Threads – Wait/Notify
notify() notifies one of the waiting thread to wake up
notify() does not release the lock on obj. notify() should be called only after
obtaining the lock synchronized (obj) {
obj.notify(); }
Copyright 2003 Mudra Services
102
Threads – Wait/Notify notifyAll notifies all the threads which
are waiting (not only one thread) But only one thread at a time will wake up
from the wait. notifyAll() should be called only after
obtaining the lock
synchronized (obj) { obj.notifyAll();}
Copyright 2003 Mudra Services
103
Threads – Message Queue Example
MessageQueueObject
Main Thread MessageQueue Thread
Copyright 2003 Mudra Services
104
Threads – Example
A typical Message Queue [with problems]package threads;import java.util.*;public class MessageQueue extends Thread { private ArrayList list = new ArrayList();
public void enqueue(Object o) { synchronized (list) { // enqueue the message and notify the message queue thread list.add(o); list.notify(); } }
Notify the MessageQueue thread to handle message
Copyright 2003 Mudra Services
105
Threads – Example
public void run() { try { while(true) { synchronized (list) { // wait till a message is enqueued list.wait();
Object o = list.remove(0); System.out.println("Handling " + o); } } // end while } catch(InterruptedException exp) { System.out.println("MessageQueue thread interrupted"); } }
Wait till a message is queued. Then wakeup and handle it.
An interrupt willterminate the thread
Copyright 2003 Mudra Services
106
Threads – Example
public static void main(String[] args) {
// start the message queue thread MessageQueue messageQueue = new MessageQueue(); messageQueue.start();
// Add messages to the message queue messageQueue.enqueue("message1"); messageQueue.enqueue("message2"); messageQueue.enqueue("message3"); }
} // end MessageQueue
Copyright 2003 Mudra Services
107
Threads – Issues with wait/Notify
Two problems with the above example Missed Notification
A notify() is called before the thread calls the wait()
The thread misses the notification Early notification (spurious wakeups)
A notify() is called but was not the right one
The thread thinks incorrectly that the condition is met
Copyright 2003 Mudra Services
108
Threads – Example
while loop used to check if the condition is true If block will not work
synchronized (list) {
// wait till a message is enqueued while (list.isEmpty()) { list.wait(); } …. } // end synchronized
Copyright 2003 Mudra Services
109
Threads – Idiom to use Wait
Always use the wait loop idiom to invoke the wait method
synchronized (obj) { while (<condition does not hold>) { obj.wait(); }
// perform action appropriate to actions}
Copyright 2003 Mudra Services
110
Threads – notify/notifyAll
Use notify() if only one thread is in the wait state If only one thread at a time can benefit from
waking up
notifyAll Use when all threads need to wakeup In general this is preferred Performance implications Only one thread will be inside the synch block
at a time
Copyright 2003 Mudra Services
111
Exercise 4
Type in the SearchExample.java defined earlier and see that it works.
Modify the SearchExample.java to support progress bar for the find.
When the search button is pressed, the progress bar should move from 0 to 100% in a minute. The label should say Found on reaching 100%
When cancel is pressed, the progress bar should clear to 0 and label should change to Cancelled
Copyright 2003 Mudra Services
112
Threads – join
Several methods join() // unlimited wait
join(long) // wait millsec or thread death
Current thread blocks till the thread dies Throws InterruptedException if
interrupted while waiting for the specified thread to die
Copyright 2003 Mudra Services
113
Threads – join
try {// current thread will wait till ‘thread’ dies
thread.join();}catch (InterruptedException exp) { // handle interruption}
Copyright 2003 Mudra Services
114
Threads – Priority
getPriority Gets the priority of the thread
setPriority Sets the priority of the thread Three priorities defined
Thread.MAX_PRIORITY Thread.MIN_PRIORITY Thread.NORM_PRIORITY
Copyright 2003 Mudra Services
115
Threads – Priority
General tips for setting priority Use higher priorities for threads which block
frequently and are shortlived (pinging thread) CPU intensive threads should be medium to
low priority (find thread)
Thread.yield() Yields it’s processor time to other threads It’s possible that threads of lower priority can
take the processor time.
Copyright 2003 Mudra Services
116
Threads – Daemon Threads
Background supporting tasks Only needed when other non-daemon
tasks are running VM exits when there are only daemon
threads running Daemon threads are stopped in their
tracks Not even the finally block is executed.
Copyright 2003 Mudra Services
117
Threads – Daemon Threads
Setting the Daemon status of a thread thread.setDaemon(true) Makes the thread a daemon VM will not wait for this thread to stop
before exiting
Make sure that it is not harmful to exit in this fashion Database connection not released etc
Copyright 2003 Mudra Services
118
Threads – Thread Groups
Threads can be grouped together into a thread group
A ThreadGroup can contain threads as well as ThreadGroups
All threads belong to exactly one thread group
All thread groups have exactly one parent
There is one root thread group which contains all threads and thread groups
Copyright 2003 Mudra Services
119
Threads – Thread Groups
Create a new ThreadGroup object// parent of group is the threadgroup of the calling threadThreadGroup group
= new ThreadGroup("User Request Group");
Creating a Thread in the group// group is the threadgroup of threadThread thread = new Thread(group,runner);
// threadgroup of thread is the threadgroup of the calling thread
Thread thread = new Thread(runner)
Copyright 2003 Mudra Services
120
Threads – Thread Groups
setMaxPriority getMaxPriority interrupt stop // deprecated suspend // deprecated resume // deprecated enumerate activeGroupCount activeThreadCount
Copyright 2003 Mudra Services
121
Threads – Problems of Synchronization
Performance Issues Synchronization is costly Code inside the synchronization blocks must
be reduced to the bare minimum
Deadlock problems Over synchronization can lead to deadlock
conditions
Copyright 2003 Mudra Services
122
Threads – Performance
Do not synchronize methods which access variables which are never changed
Lock contention reduction.
Copyright 2003 Mudra Services
123
Threads – Deadlocks
Do as little work as possible inside the synchronized block
Example of a modified abstract MessageQueue
Any Queue can make use of MessageQueue by extending it. Maybe the Swing Event Thread
Copyright 2003 Mudra Services
124
Threads – Deadlockspackage threads;import java.util.*;public abstract class MessageQueue extends Thread { private ArrayList list = new ArrayList(); public void run() { try { while(true) { synchronized (list) { // wait till a message is enqueued while (list.isEmpty()) { list.wait(); } Object o = list.remove(0);
// handle the message handleMessage(o); } // end synchronization
Copyright 2003 Mudra Services
125
Threads – Deadlocks
} // end while } catch(InterruptedException exp) { System.out.println("MessageQueue thread interrupted"); } }
public void enqueue(Object o) { synchronized (list) { // enqueue the message and notify the message queue thread list.add(o); list.notify(); } }
protected abstract void handleMessage(Object o);}
Copyright 2003 Mudra Services
126
Threads – Deadlocks
Faulty implementation of MessageQueue can lead to deadlocks
Imagine an implementation in which handleMessage() creates a new thread T and joins on it.
T later tries to enqueue a message in the same queue
Move the handleMessage() method outside the synchronized block
This ensures that there is no possibility of a deadlock taking place.
Copyright 2003 Mudra Services
127
Threads – Deadlocks
Lock Object(list)
MessageQueue Thread (MQ)
Secondary Thread
lock
T
T.join()
- MQ obtains lock- MQ starts T- MQ waits for T to finish- T enqueues message
------- DEADLOCK ----------
Copyright 2003 Mudra Services
128
Threads – Deadlocks
Always suspect code which calls an alien method from inside the synchronized block
The called method might also be synchronized.
Always maintain a lock order Locks should be obtained and released in a particular
order
lock1 lock2
Copyright 2003 Mudra Services
129
Threads – Traversal
Traversing a vector Thread unsafe
for(int j=0; j < list.size(); j++) { Object o = list.get(j); handle(o);}
Thread safe put bad performancesynchronized (list) {
for(int j=0; j < list.size(); j++) { Object o = list.get(j); handle(o); } }
List can be changed by another thread
handle() method mighttake long time
Copyright 2003 Mudra Services
130
Threads – Traversal
If handle() takes a long time then a better approach might be
Object snapshot;synchronized (list) { snapshot = new Object[v.size()]; for(int j=0; j < snapshot.length; j++) { snapshot[j] = list.get(j); }} // end synchronized
for (int j=0;j < snapshot.length;j++) { handle(o);}
Take snapshot
Call handle()outside synch block
Copyright 2003 Mudra Services
131
Threads – Splitting Synchronization
Creating subsets for synchronization
class Shape {
protected double x = 0.0; protected double y = 0.0; protected double width = 0.0; protected double height = 0.0;
public synchronized double x() { return x; } public synchronized double y() { return x; } public synchronized double width() { return width; } public synchronized double height() { return height; }
Copyright 2003 Mudra Services
132
Threads – Splitting Synchronization
public synchronized void adjustLocation() { x = longCalculation1(); y = longCalculation2(); }
public synchronized void adjustDimensions() { width = longCalculation3(); height = longCalculation4(); }
// .....
} // end Shape
Copyright 2003 Mudra Services
133
Threads – Splitting Locks
Use two locks instead of one
class Shape {
protected double x = 0.0; protected double y = 0.0; protected double width = 0.0; protected double height = 0.0;
protected final Object locationLock = new Object(); protected final Object dimensionLock = new
Object();
Copyright 2003 Mudra Services
134
Threads – Splitting Locks
public double x() { synchronized (locationLock) { return x; } }
public double y() { synchronized (locationLock) { return y; } }
Copyright 2003 Mudra Services
135
Threads – Splitting Locks
public double width() { synchronized (dimensionLock) { return width; } }
public double height() { synchronized (dimensionLock) { return height; } }
Copyright 2003 Mudra Services
136
Threads – Splitting Locks
public void adjustLocation() { synchronized (locationLock) { x = longCalculation1(); y = longCalculation2(); } } public void adjustDimensions() { synchronized (dimensionLock) { width = longCalculation3(); height = longCalculation4(); } } // .....} // end Shape
Copyright 2003 Mudra Services
137
Threads – Splitting classes
Can also split classes
class PassThroughShape {
private final AdjustableLoc loc = new AdjustableLoc(0,0); private final AdjustableDim dim = new AdjustableDim(0,0);
public double x() { return loc.x(); } public double y() { return loc.y(); }
public double width() { return dim.width(); } public double height() { return dim.height(); }
public void adjustLocation() { loc.adjust(); } public void adjustDimension() { dim.adjust(); }}
Copyright 2003 Mudra Services
138
Threads – mutex
Mutual exclusion lock
interface Mutex { void aquire() throws InterruptedException; void release(); boolean attempt(long msec) throws InterruptedException;}
aquire Analogous to operations performed on entry
to synchronized block
Copyright 2003 Mudra Services
139
Threads – mutex
release Analogous to operation performed while
leaving the synchronized block
attempt Returns TRUE if the lock is acquired within
the time
Copyright 2003 Mudra Services
140
Threads – mutex
synchronized (lock) {
/* BODY */}
try { mutex.acquire(); try { /* BODY */ } finally { mutex.release(); }}catch (InterruptedException exp) { // handle thread cancellation}
Copyright 2003 Mudra Services
141
Threads – mutex
Ability to wait for a specified amount of time
Reduces the chances of deadlocks Highly responsive to cancellation
(interrupts) Handles the interrupted exception cleanly
Copyright 2003 Mudra Services
142
Threads – Documentation
Every class created should be documented for thread safety
Documentation should clearly mention if the class and it’s methods are thread safe
Should client synchronize. If so on which lock should be held and so on.
Copyright 2003 Mudra Services
143
Exercise 5
Design a class called Lock, which implements Mutex interface as described before in the class. Use wait/notify scheme to create the class.
BooleanLock utility described in the book is very similar to this class.