COMP201 Java Programming
Part III: Advanced Features
Topic 12: Multithreading
Volume II,Chapter 1
COMP201 Topic 13 / Slide 2
Outline
Introduction: Why and what Basics: creating and running threads
Issues Thread states Thread scheduling Synchronization Suspending and stopping threads
Threads and Swing
COMP201 Topic 13 / Slide 3
Introduction
Consider the program Bounce.java Desired effects
– If the Start button is clicked, a ball starts to bounce.
– If the button is clicked again, a second ball starts to bounce and so on.
– If the Close button is clicked, the windows closes and the program terminates
Classes– Ball
– BallPanel extends JPanel
– BounceFrame extends JFrame
– Bounce
COMP201 Topic 13 / Slide 4
Introduction
Classes Ball
– public Ellipe2D getShape()
Gets the shape of the ball at its current position– public void move()
Moves the ball to the next position, reversing direction if it hits one of the edges
class BallPanel extends JPanel– Keeps a list of balls = new ArrayList<Ball>();– public void add(Ball b)
Add a ball to the Panel.– public void paintComponent(Graphics g)
Draw all balls at their current positions
COMP201 Topic 13 / Slide 5
Introduction Classesclass BounceFrame extends JFrame
Set up GUI and listeners When the Close button is clicked this method is called,
public void actionPerformed(ActionEvent evt) { System.exit(0); }
When the Start Button is clicked, this method is called public void actionPerformed(ActionEvent evt) { addBall();
//Creates and adds a bouncing ball to the panel // and make it bounce 1,000 times.
}
COMP201 Topic 13 / Slide 6
Introduction
public void addBall() { try { Ball ball = new Ball(); panel.add(ball); for (int i = 1; i <= STEPS; i++) { ball.move(panel.getBounds()); panel.paint(panel.getGraphics()); Thread.sleep(DELAY); } } catch (InterruptedException e) {} } Note: sleep is a static method that puts the currently running thread to
sleep. It throws InterruptedException when interrupted.
COMP201 Topic 13 / Slide 7
Introduction
However
Cannot start a second ball before the current ball finishes bouncing
Cannot terminate program before the current ball finishes bouncing
Actually, won’t even work if repaint() is used (as it should be) instead of paint.
COMP201 Topic 13 / Slide 8
Introduction Why?
There is a single thread of control.
Actions are executed one by one.
Cannot execute next action before current action finishes
Implications in general: Cannot do anything else while waiting data from the net. Cannot stop downloading even though you know, after seeing
part of the download, that you don’t want the download any more
Solution: Multithreading
COMP201 Topic 13 / Slide 9
Introduction
A multithreaded program has multiple threads of control OS runs one thread a short period of time, then switches to another, and
so on To user, threads appear to run simultaneously. An illusion. Nonetheless, makes it easier for user to interact with program
COMP201 Topic 13 / Slide 10
Introduction In our example, we need more than one thread:
One thread to listen for button clicks
One thread to bounce each ball
//BounceThread.java
COMP201 Topic 13 / Slide 11
Outline
Introduction: Why and what Basics: creating and running threads
Issues Thread states Thread scheduling Synchronization Suspending and stopping threads
Threads and Swing
COMP201 Topic 13 / Slide 12
How to create and run new threads (from the current thread)?1. Write a class that implements the interface java.lang.Runnable class MyRunnable implements Runnable { public void run(){ task code }}2. Construct an object of your class: Runnable r = new MyRunnable();3. Construct a Thread object from the Runnable: Thread t = new Thread(r);4. Start the thread: t.start();Don’t call run, it just executes the task in the same thread, no new thread is
started.
Creating and Running Threads
COMP201 Topic 13 / Slide 13
Creating and Running Threads
class BallRunnable implements Runnable
{ ……
public void run()
{ try
{ for (int i = 1; i <= STEPS; i++)
{ ball.move(component.getBounds());
component.repaint();
Thread.sleep(DELAY);
}
}catch (InterruptedException e){}
}
private Ball ball;
private Component component; …} //BounceThread.java
Invoke the addball() when “Start” button is clicked
addButton(buttonPanel, "Start",new ActionListener()
{ public void actionPerformed(ActionEvent event)
{ addBall();}
});
public void addBall()
{
Ball b = new Ball();
panel.add(b);
Runnable r = new BallRunnable(b, panel);
Thread t = new Thread(r);
t.start();
}
private BallPanel panel;
COMP201 Topic 13 / Slide 15
Outline
Introduction: Why and what Basics: creating and running threads
Issues Thread states Thread scheduling Synchronization Suspending and stopping threads
Threads and Swing
COMP201 Topic 13 / Slide 16
Thread States Four states for threads: new, runnable, blocked, dead
newstart
dead
Note: suspend, resume,stop deprecated.
runnable
run exitsstop
blocked
sleep
done sleepingsuspend
resume
wait notify
block on I/O
I/O complete
Wait for lock
Lock available
COMP201 Topic 13 / Slide 17
Thread States When a thread has just been created using the new operator, it is in
the new state.
Once start method is invoked (which calls the run method), the thread becomes runnable. A runnable thread might not be running. There can be many runnable threads. But only one of them can be
running at any time point. OS decides which thread to run. More on this later.
new
runnable
start
COMP201 Topic 13 / Slide 18
Thread States A runnable thread enters the blocked state when
1. The thread is currently running and method Thread.sleep is called 2. suspend method of the thread is called. (deprecated)3. The thread calls the wait method.4. The thread tries to lock an object locked by another thread.5. The thread calls an operation that is blocked on i/o.
runnable
blocked
sleep
suspend
wait
block on I/O
Wait for lockA blocked thread cannot be running
COMP201 Topic 13 / Slide 19
Thread States A blocked reenters runnable state when
1. It has slept the specified amount of time.2. resume method of the thread is called. (deprecated)3. Another method calls notify or notifyAll 4. Object lock released by another thread5. I/O completed.
runnable
blockeddone sleeping
resume
notify
I/O completeLock available
COMP201 Topic 13 / Slide 20
Thread States A runnable thread enters the dead state when
Its run method exits. Natural death. stop method of the thread is called. (deprecated) An exception is thrown but not caught.
dead
runnable
run exitsstop
COMP201 Topic 13 / Slide 21
Thread States
Finding out states of threads
Method isAlive allows you to find out whether a thread is alive or dead.
– This method returns true if the thread is runnable or blocked,
– false if the thread is still new and not yet runnable or if the thread is dead
No way to find out whether an alive thread is running, runnable, or blocked.
COMP201 Topic 13 / Slide 22
Outline
Introduction: Why and what Basics: creating and running threads
Issues Thread states Thread scheduling Synchronization Suspending and stopping threads
Threads and Swing
COMP201 Topic 13 / Slide 23
Thread Scheduling At any time, there might be many runnable threads. But only one of them is
actually running. The thread scheduler decides which runnable thread to run.
Questions: When does the thread scheduler kick in and pick a thread to run? How does the thread scheduler select among the runnable threads?
A not-so-precise answer: A running Java thread will continue to run until
– It calls yield method, or– It ceases to be runnable (dead or blocked), or – Another thread with higher priority moves out of blocked state
Then the thread scheduler kicks in and picks another thread with the highest priority to run
COMP201 Topic 13 / Slide 24
Thread Scheduling
Two different thread implementations
“Native thread” implementation (e.g. Windows): Performs time-slicing. Interrupts the running thread periodically to give
other threads a chance to run.
“Green thread” implementation (e.g. Solaris) Does not perform time-slicing. It keeps a running thread active until a
higher-priority thread awakes and takes control.
COMP201 Topic 13 / Slide 25
Thread Scheduling The answer on slide 23 is precise for the green thread
implementation.
For the native thread implementation, the precise answer is A running Java thread will continue to run until
– It calls yield method, or– It ceases to be runnable (dead or blocked), or– Another thread with higher priority moves out of blocked state,
or– It is pre-emptied by OS (time-slicing).
Then the thread scheduler kicks in and picks another thread with the highest priority to run
COMP201 Topic 13 / Slide 26
Thread Scheduling
Priority of individual threads Can be increased or decreased using setPriority
– Java have 10 priority levels (constants of Thread class)
MIN_PRIORITY = 1; NORMAL_PRIORITY = 5;
MAX_PRIORITY = 10
A thread inherits priority from its parent thread, the one that creates it.
Note– Some OS has fewer. E.g. Windows NT has 7.
– JVM maps Java priority levels to priority level of the underlying OS.
COMP201 Topic 13 / Slide 27
Example: BounceExpress.java Two kinds of balls: black and red. Red ball threads have higher priority and hence get more
chance to run. The effect is that red balls appear to be moving faster.
Thread Scheduling
COMP201 Topic 13 / Slide 28
Thread Scheduling
The addBall method public void addBall(int priority, Color color) { for (int i = 0; i< 300; i++){ Ball b = new Ball( color); panel.add(b); Runnable r = new BallRunnable(b, panel); Thread t = new Thread(r); t.setPriority(priority);// priority set here t.start(); try {
Thread.sleep(1); }catch(InterruptedException exception)
{}; }
}
COMP201 Topic 13 / Slide 29
Thread Scheduling
Buttons and listeners addButton(buttonPanel, "Start", new ActionListener() { public void actionPerformed(ActionEvent evt) { addBall(Thread.NORM_PRIORITY - 2, Color.black); }});
addButton(buttonPanel, "Express", new ActionListener() { public void actionPerformed(ActionEvent evt) { addBall(Thread.NORM_PRIORITY + 2, Color.red); } });
COMP201 Topic 13 / Slide 30
Question 1: Consider the case when there are 1 black ball and 1 red ball. When the red-ball thread goes to sleep, there is only one other thread,
the black-ball thread. Hence the black-ball thread must be chosen. Implication:
– black ball takes one move, red ball takes one move, black ball takes one move, and so on.
– The two balls should be of the same speed. Well, this is not the case. Why?
There is another thread! What is it? What role does it play? When event dispatch thread pauses, the red-ball thread already wake
up from sleep and hence picked by scheduler over back-ball thread.
Thread Scheduling
COMP201 Topic 13 / Slide 31
Question 2: If we change sleeping to 50 or running the program on a faster cpu,
red balls are not faster any more. Why? In order for the red-ball thread to be picked more often than the
black-ball thread, it must “meet” the scheduler more often. When event dispatch thread pauses, the red-ball thread is still
sleeping, just as the black-ball thread.
Thread Scheduling
COMP201 Topic 13 / Slide 32
sleep vs. yield
In BallRunnable, sleep is called to give other thread a chance to run. Another way is to call yield.
class BallRunnable implements Runnable{
public BallRunnable(Ball aBall, Component aComponent)
{ ball = aBall;
component = aComponent; }
public void run() // codes for new thread
{ for ( int i = 1; i <= STEPS; i++)
{
ball.move(component.getBounds());
component.repaint();
Thread.yield();
} }}
COMP201 Topic 13 / Slide 33
sleep vs. yield
There is a big difference Calling sleep put the current running thread into the blocked state Calling yield does not put the calling thread, t1, into the blocked
state– It merely let the scheduler kick in and pick another thread to run.– It might happen that the t1 is select to run again. This happens
when t1 has a higher priority than all other runnable threads.
COMP201 Topic 13 / Slide 34
Thread Scheduling Cooperating vs. Selfish threads:
A cooperating thread gives others a chance to run Calling sleep: pause for the specified period of time Calling yield: pause temporarily. Scheduler kicks in.
A selfish thread does none of this.
Effects of selfish threads are system-dependent: Green thread: A selfish thread can consume all the CPU time. Native thread: A selfish thread doesn’t post a big problem.
COMP201 Topic 13 / Slide 35
Thread Schedulingpublic void run()
{ try
{for (int i = 1; i <= STEPS; i++)
{ ball.move(component.getBounds());
component.repaint();
if (ball.getSelfish())
{ // busy wait for 5 milliseconds
long t = System.currentTimeMillis();
while (System.currentTimeMillis()<t + 5)
;
}
else Thread.sleep(DELAY);
}catch (InterruptedException exception){}
} //BounceSelfish.java
COMP201 Topic 13 / Slide 36
Question 3: The balls some times jump. Why?
Event dispatch thread doesn’t get the time to run. Paint events accumulate.
Thread Scheduling
COMP201 Topic 13 / Slide 37
Outline
Introduction: Why and what Basics: creating and running threads
Issues Thread states Thread scheduling Synchronization Suspending and stopping threads
Threads and Swing
COMP201 Topic 13 / Slide 38
Synchronization The Synchronization problem:
Two different threads modify the same object at the same time, leading to corrupted object. Such a situation is called race condition.
An analog: You and your partner are finishing a group project and starting to write
the project report. The report is kept at a centralized location.
– You open the report and edit it
– Your partner opens the report and edits it
– You save the edits.
– Your partner saves his edits, Your edits are lost!
COMP201 Topic 13 / Slide 39
An example: UnsynchBankTest.java class Bank
– A bank with a number of bank accounts.
class TransferRunnable implements Runnable - A runnable that transfers money from an account to other
accounts in a bank.
public class UnsynchBankTest– Create 10 accounts and multiple threads to make random transfers
Synchronization
COMP201 Topic 13 / Slide 40
public void transfer(int from, int to, int amount){ if (accounts[from] < amount) return ; accounts[from] -= amount; // added by Instructor so that corruption occurs
//more easily try { Thread.sleep(3); } catch(InterruptedException e) {}
accounts[to] += amount; counter++; //print out total after every 1000 transactions if (counter %1000 == 0){ System.out.print(Thread.currentThread()); System.out.printf(" %10.2f from %d to %d",
amount, from, to); System.out.printf(" Total Balance: %10.2f%n",
getTotalBalance()); }
Synchronization
COMP201 Topic 13 / Slide 41
Synchronization class TransferRunnable implements Runnable{ public TransferRunnable, int from, double max) {…} public void run() { try { while (true) { int toAccount = (int)(bank.size() * Math.random()); double amount = maxAmount * Math.random();
bank.transfer(fromAccount, toAccount, amount); Thread.sleep((int)Delay * Math.random()); }} catch(InterruptedException e) {} } private Bank bank; private int fromAccount; private double maxAmount; private int DELAY = 1000;
COMP201 Topic 13 / Slide 42
Synchronization Class UnsynchBankTest
public static void main(String[] args) { Bank b = new Bank(NACCOUNTS, INITIAL_BALANCE); int i; for (i = 0; i < NACCOUNTS; i++) { TransferRunnable r = new
TransferRunnable(b, i, INITIAL_BALANCE); Thread t = new Thread(r); t.start(); } } public static final int NACCOUNTS = 10; public static final int INITIAL_BALANCE = 10000;
Note: Total amount in all accounts = 100,000
COMP201 Topic 13 / Slide 43
Synchronization
Run the program
Very quickly, the amounts in the accounts do not add up to 100,000
Why?– The transfer method of Bank class is not atomic: consists of many steps
– Can be interrupted in the middle
COMP201 Topic 13 / Slide 44
Problem scenario: Thread 1 takes 50 from account A Goes to sleep (simulate interruption, self interruption) Thread 2 completes transfer and call test Result:
– 50 less in total
The total amount can only be less than 100,000 If we swap the deduction and addition, the total will always
be more.
Synchronization
COMP201 Topic 13 / Slide 45
Synchronization Note that even instructions are not atomic.
Consider the following accounts[to] += amount;
It is processed in three steps as follows:1. Load current value of accounts[to] to a register2. Add amount3. Move the result back to accounts[to].
COMP201 Topic 13 / Slide 46
Synchronization Execution interruption
accounts[0] is currently 100. Thread 1 performaccounts[0] += 50;
Thread 2 performs accounts[0] += 50; The correct result should be: accounts[0] == 200. What is the result if the following happens?
Actual result: accounts[0] == 150The probability of such interruptions is low (but possible). This
is why we faked interruption using sleep.
Thread 1 Steps 1, 2 Step 3
Thread 2 Steps 1, 2, 3
COMP201 Topic 13 / Slide 47
ReentrantLock How to avoid the work of the transfer method being interrupted? JDK 5.0
introduces the Reentrantlock class
class Bank
{ …
public void transfer( int from, int to,int amount){
bankLock.lock();
try{ if (accounts[from] < amount ) return;
accounts[from] -= amount;
try {Thread.sleep(1);}catch(InterruptedException e) {}
accounts[to] += amount; …
}
finally {bankLock.unlock();} }….
Private Lock bankLock= new Reentrantlock ();
//Reentrantlock implements the Lock interface.
} // SynchronizedBankTest0.java
COMP201 Topic 13 / Slide 48
ReentrantLock How does the mechanism work?
This construct guarantees that only one thread at a time can enter the critical section. As soon as one thread locks the lock object, no other thread can get past the lock statement. When other threads call lock they are blocked until the first thread unlocks the lock object.
Suppose one thread calls transfer and gets preempted before it is done. Suppose a second thread also calls transfer . The second thread cannot acquire the lock and is blocked in the call to the lock method. It is deactivated and must wait for the first thread to finish executing the transfer method. When the first thread unlock the lock, then the second thread can proceed.
The lock is called reentrant because a thread can repeatedly acquire a lock that it already owns. The lock keeps a hold count that keeps track of the nested calls to the lock method. The thread has to call unlock for every call to lock in order to relinquish the lock. So code that is protected by a lock can call another method that uses the same lock.
–
COMP201 Topic 13 / Slide 49
Condition Object Often, a thread enters a critical section, only to discover that it can’t
proceed until a condition is fulfilled. JDK5.0 uses a condition object to manage threads that have acquired a lock but cannot do useful work.
For example, what do we do where there is not enough money in the account? We wait until some other thread has added funds. But this thread has just gained exclusive access to the banklock, so no other thread has a chance to make a deposit. This is where condition object come in.
A lock object can have one or more associated condition objects. You obtain a condition object with the newCondition method. It is customary to give each condition object a name that evokes the condition that it represents. For example:
private Condition sufficientFunds; sufficientFunds = bankLock.newCondition ();
COMP201 Topic 13 / Slide 50
Condition Object If the transfer method finds that sufficient funds are not available, it calls
sufficientFunds.await(); The current thread is now blocked and gives up the lock. This lets in
another thread that can (possibly) increase the account balance. When another thread transfers money, it should call
sufficientFunds.signalAll(); to unblock all threads that are waiting for the condition.
or call sufficientFunds.signal(); to unblock a single thread from the wait set, chosen at random.
When the threads are removed from the wait set, they are again runnable and the scheduler will eventually activate them again. At that time, they will attempt to reenter the object. As soon as the lock is available, one of them will acquire the lock and continue where it left off, returning from the await. At this time the thread should test the condition again. There is no guarantee that the condition is now fulfilled.
COMP201 Topic 13 / Slide 51
Condition Object It is crucial that some other thread calls the signalAll eventually.
When a thread calls await, it has no way of unblocking itself. It puts its faith in the other thread. If none of them bother to unblock the waiting thread, it will never run again. This can lead to deadlock situation. class Bank
{ public void transfer( int from, int to,int amount)
bankLock.lock();
try{
if (accounts[from] < amount ) sufficientFunds.await();
//transfer money
sufficientFunds.signalall();
}
finally {bankLock.unlock();}
Private Lock bankLock= new Reentrantlock ();
} // SynchronizedBankTest.java
COMP201 Topic 13 / Slide 52
Synchronization Another easy way to avoid the work of the transfer method being interrupted is to make
the method synchronized.class Bank { … public synchronized void transfer( int from,
int to,int amount) { while (accounts[from] < amount ) return;
accounts[from] -= amount;
try { Thread.sleep(3); } catch(InterruptedException e) {}
accounts[to] += amount; ntransacts++; if (ntransacts % 1000 == 0) //output balance}
} // SynchronizedBankTest2.java
COMP201 Topic 13 / Slide 53
Synchronization
How does the mechanism work? Object locks
– When a thread calls a synchronized method of an object, the object is locked.
– All other threads that try to call synchronized methods of the object are blocked.
The thread inside the object can of course call all synchronized methods
Threads that call unsynchronized methods of the object can proceed.
– When the thread that locked the object finishes or terminates because of uncaught exception, it relinquishes the object lock
– Periodically, the thread scheduler activates the threads waiting for the lock. They all become runnable.
– When one of the blocked threads is scheduled to run, it checks to see if the object is locked. If not, it proceeds and locks the object.
COMP201 Topic 13 / Slide 54
Synchronization
In the bank example, if a thread is executing b.transfer(…), it locks the Bank object b.
While b is locked, other threads trying to call b.transfer(…) are blocked.
b.transfer(…) is not interrupted.
COMP201 Topic 13 / Slide 55
Synchronization
When the thread that locks b finishes, it gives up the object lock. The “door” is again open.
Periodically, the thread scheduler unblocks all threads waiting for the object lock
When such a thread is scheduled to run again, it checks whether b is still locked. If not, it proceeds and locks b.
Otherwise, it becomes blocked again.
COMP201 Topic 13 / Slide 56
Synchronization
Note that SynchronizedBankTest2.java is much slower than UnsynchronizedBankTest.java Other threads trying to get into an bank account cannot do
so if it is locked by another thread, even that thread is sleeping inside!
Synchronization takes time. Reason why not all methods are synchronized. In particular, most methods of classes in Swing are not
synchronized.– Swing is not thread-safe.
COMP201 Topic 13 / Slide 57
Synchronization/wait and notify
What to do when the from account does not have sufficient fund?
Currently, transfer simply return
public synchronized void transfer(int from, int to, int amount)
{ if (accounts[from] < amount) return ;
Obviously not good solutions.
COMP201 Topic 13 / Slide 58
Synchronization/wait and notify
How about this?public void synchronized transfer(int from, int to, int amount)
{ while (accounts[from] < amount) { try { Thread.sleep(5); }catch(InterruptedException e) {} }
The idea is The balance of the from account might increase after 5 milliseconds
But does not work: A sleeping thread does not relinquishes its object locks In the case, no other threads can get in the bank object and make transfers Account balances will be the same when the thread wakes up.
COMP201 Topic 13 / Slide 59
Synchronization/wait and notify
Solution: Call wait instead of sleep.
public synchronized void transfer(int from, int to, int amount)
{ while (accounts[from] < amount)
{ try { wait(); }
catch(InterruptedException e) {}
}
…}
How does this work?
COMP201 Topic 13 / Slide 60
Synchronization/wait and notify
wait
notifyAll
COMP201 Topic 13 / Slide 61
wait is a method of the Object class. It causes the calling method to wait (blocked) until notified (when another thread calls notify or notifyAll)
While waiting, a thread relinquishes its object locks. This gives other thread a chance to access the object.
notify or notifyAll are all methods of the Object class. notify randomly selects a thread among those waiting for an
object lock (inside the object) and unblocks it.
notifyAll unblocks all threads waiting for an object lock (inside the object). Preferred because it reduces the probability of deadlock (Exercise: Why is this?).
Note: wait, notify and notifyAll can only be called within synchronized methods.
Synchronization/wait and notify
COMP201 Topic 13 / Slide 62
In our example, a thread calls notifyAll when it is done with a object.
public synchronized void transfer(int from, int to, int amount)
{ while (accounts[from] < amount) { try { wait(); } catch(InterruptedException e) {} } … notifyAll();
…}
Synchronization/wait and notify
SynchBankTest3.java
COMP201 Topic 13 / Slide 63
DeadlockThe Dining-Philosophers’ Problem
COMP201 Topic 13 / Slide 64
Synchronization/Deadlock
Deadlock occurs when a number of threads waiting for each other
Example:Account 1: $2,000Account 2: $3,000Thread 1: Transfer $3,000 from account 1 to account 2Thread 2: Transfer $4,000 from account 2 to account 1
It is the responsibility of programmer to avoid deadlocks.
COMP201 Topic 13 / Slide 65
Outline
Introduction: Why and what Basics: creating and running threads
Issues Thread states Thread scheduling Synchronization Suspending and stopping threads
Threads and Swing
COMP201 Topic 13 / Slide 66
Stopping and Suspending Threads The stop method is deprecated because it can corrupt
objects.
Consider a thread that is transferring money from one account to another.
If the thread is stopped after withdrawal from the first account and before deposit to the second account, an error arises.
(Other threads can continue since the stopped thread releases all locks.)
COMP201 Topic 13 / Slide 67
Stopping and Suspending Threads The suspend and resume methods are deprecated
because they can easily lead to deadlocks. (Suspended threads do not release object locks.)
Suppose you suspend a thread t1, and t1 has locked an object x.
Further suppose t2 is responsible to resume t1 but it needs to access a synchronized method of x before resume t1.
Then, deadlock results. The resume method is deprecated because suspend is.
How to suspend a thread safely? Use the wait and notifyAll methods
Suspend by calling wait and resume using notifyAll
1. Write a class so that we can use its objects for locks
public class suspenderRequestor{ public synchronized void set ( boolean b) { suspendRequested = b; notifyAll();} public synchronized void waiteForResume() throws InterruptedException { while ( suspendRequested) wait (); }
private boolean suspendRequested}
2. Structure your thread class as follows
public class MyThread extends Thread
{ public void requestSuspend()
{ suspender.set( true ); }
public synchronized void requestResume()
{ suspender.set(false);}
public void run ()
{ while ( more work to do)
{ suspender.waitForResume(); // call this once in a while do more work;
} }
private SuspendRequestor suspender
= new SuspendRequestor();
}
To suspend and resume a thread t, call
t.requestSuspend(); t.requestResume();
COMP201 Topic 13 / Slide 70
Outline
Introduction: Why and what Basics: creating and running threads
Issues Thread states Thread scheduling Synchronization Suspending and stopping threads
Threads and Swing
COMP201 Topic 13 / Slide 71
Threads in Swing Every Java application start with a main method which runs in a
main thread. The main method typically call a constructor that lays out components in a frame window Invoke the setVisible method
When the first window is shown a second thread is created, the event dispatch thread. All event notifications, such as actionPerformed or painComponent, run in the event dispatch thread.
From the event dispatch thread, one wants to fire up threads for
Time-consuming actions
Actions that can be blocked on I/O
Sleeping
Otherwise, GUI might seem dead or frozen.
COMP201 Topic 13 / Slide 72
Threads and Swing Caution: Swing is not thread safe!
Most methods in Swing classes are not synchronized. If one tamper with UI components from different threads, UI
might be corrupted.
Single thread rule for Swing programming Read any information from the UI before you launch your
threads, launch them, and then update the UI from the event dispatch thread.
Other threads should send actions that modify UI components to the event dispatch thread using the invokeLater or invokeAndWait methods of the EventQueue class (see textbook for details.)//swingThreadTest.java
public SwingThreadFrame()
{ setTitle("SwingThreadTest");
final JComboBox combo = new JComboBox();
….
JPanel panel = new JPanel();
JButton goodButton = new JButton("Good");
goodButton.addActionListener(new ActionListener()
{ public void actionPerformed(ActionEvent event)
{ new Thread(new GoodWorkerRunnable(combo)).start(); } });
panel.add(goodButton);
JButton badButton = new JButton("Bad");
badButton.addActionListener(new ActionListener()
{ public void actionPerformed(ActionEvent event)
{ new Thread(new BadWorkerRunnable(combo)).start();
} });
panel.add(badButton);
panel.add(combo);
add(panel);
pack();}}
class BadWorkerRunnable implements Runnable{ public BadWorkerRunnable(JComboBox aCombo)
{ combo = aCombo;
generator = new Random();}
public void run()
{try
{ while (true)
{ combo.showPopup();
int i = Math.abs(generator.nextInt());
if (i % 2 == 0)
combo.insertItemAt( new Integer(i), 0);
else if (combo.getItemCount() > 0)
combo.removeItemAt(i % combo.getItemCount());
Thread.sleep(1);
}
}catch (InterruptedException e) {}}
private JComboBox combo;
private Random generator;}
class GoodWorkerRunnable implements Runnable{ public GoodWorkerRunnable(JComboBox aCombo)
{ combo = aCombo;
generator = new Random();}
public void run()
{try{ while (true)
{ EventQueue.invokeLater(new Runnable()
{ public void run()
{
combo.showPopup();
int i = Math.abs(generator.nextInt());
if (i % 2 == 0)
combo.insertItemAt(new Integer(i), 0);
else if (combo.getItemCount() > 0)
combo.removeItemAt(i % combo.getItemCount());
} });
Thread.sleep(1);
}}catch (InterruptedException e) {} }
private JComboBox combo; private Random generator;}
COMP201 Topic 13 / Slide 76
Summary of classes and methods
public class Thread extends Object implements Runnable Thread() , Thread(Runnable target) Constants: MAX_PRIORITY NORMAL_PRIORITY, MIN_PRIORITY
static: sleep, yield, interrupted start, run, setPriority, setPriority, interrupt isAlive, isInterrupted
public interface Runnable run
public class Object wait, notify, notifyAll
public class InterruptedException extends Exception