COMP201 Java Programming Part III: Advanced Features Topic 12: Multithreading Volume II,Chapter 1.

76
COMP201 Java Programming Part III: Advanced Features Topic 12: Multithreading Volume II,Chapter 1
  • date post

    21-Dec-2015
  • Category

    Documents

  • view

    230
  • download

    0

Transcript of COMP201 Java Programming Part III: Advanced Features Topic 12: Multithreading Volume II,Chapter 1.

Page 1: COMP201 Java Programming Part III: Advanced Features Topic 12: Multithreading Volume II,Chapter 1.

COMP201 Java Programming

Part III: Advanced Features

Topic 12: Multithreading

Volume II,Chapter 1

Page 2: 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

Page 3: COMP201 Java Programming Part III: Advanced Features Topic 12: Multithreading Volume II,Chapter 1.

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

Page 4: COMP201 Java Programming Part III: Advanced Features Topic 12: Multithreading Volume II,Chapter 1.

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

Page 5: COMP201 Java Programming Part III: Advanced Features Topic 12: Multithreading Volume II,Chapter 1.

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.

}

Page 6: COMP201 Java Programming Part III: Advanced Features Topic 12: Multithreading Volume II,Chapter 1.

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.

Page 7: COMP201 Java Programming Part III: Advanced Features Topic 12: Multithreading Volume II,Chapter 1.

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.

Page 8: COMP201 Java Programming Part III: Advanced Features Topic 12: Multithreading Volume II,Chapter 1.

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

Page 9: COMP201 Java Programming Part III: Advanced Features Topic 12: Multithreading Volume II,Chapter 1.

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

Page 10: COMP201 Java Programming Part III: Advanced Features Topic 12: Multithreading Volume II,Chapter 1.

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

Page 11: COMP201 Java Programming Part III: Advanced Features Topic 12: Multithreading Volume II,Chapter 1.

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

Page 12: COMP201 Java Programming Part III: Advanced Features Topic 12: Multithreading Volume II,Chapter 1.

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

Page 13: COMP201 Java Programming Part III: Advanced Features Topic 12: Multithreading Volume II,Chapter 1.

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

Page 14: COMP201 Java Programming Part III: Advanced Features Topic 12: Multithreading Volume II,Chapter 1.

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;

Page 15: COMP201 Java Programming Part III: Advanced Features Topic 12: Multithreading Volume II,Chapter 1.

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

Page 16: COMP201 Java Programming Part III: Advanced Features Topic 12: Multithreading Volume II,Chapter 1.

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

Page 17: COMP201 Java Programming Part III: Advanced Features Topic 12: Multithreading Volume II,Chapter 1.

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

Page 18: COMP201 Java Programming Part III: Advanced Features Topic 12: Multithreading Volume II,Chapter 1.

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

Page 19: COMP201 Java Programming Part III: Advanced Features Topic 12: Multithreading Volume II,Chapter 1.

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

Page 20: COMP201 Java Programming Part III: Advanced Features Topic 12: Multithreading Volume II,Chapter 1.

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

Page 21: COMP201 Java Programming Part III: Advanced Features Topic 12: Multithreading Volume II,Chapter 1.

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.

Page 22: COMP201 Java Programming Part III: Advanced Features Topic 12: Multithreading Volume II,Chapter 1.

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

Page 23: COMP201 Java Programming Part III: Advanced Features Topic 12: Multithreading Volume II,Chapter 1.

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

Page 24: COMP201 Java Programming Part III: Advanced Features Topic 12: Multithreading Volume II,Chapter 1.

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.

Page 25: COMP201 Java Programming Part III: Advanced Features Topic 12: Multithreading Volume II,Chapter 1.

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

Page 26: COMP201 Java Programming Part III: Advanced Features Topic 12: Multithreading Volume II,Chapter 1.

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.

Page 27: COMP201 Java Programming Part III: Advanced Features Topic 12: Multithreading Volume II,Chapter 1.

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

Page 28: COMP201 Java Programming Part III: Advanced Features Topic 12: Multithreading Volume II,Chapter 1.

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)

{}; }

}

Page 29: COMP201 Java Programming Part III: Advanced Features Topic 12: Multithreading Volume II,Chapter 1.

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); } });

Page 30: COMP201 Java Programming Part III: Advanced Features Topic 12: Multithreading Volume II,Chapter 1.

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

Page 31: COMP201 Java Programming Part III: Advanced Features Topic 12: Multithreading Volume II,Chapter 1.

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

Page 32: COMP201 Java Programming Part III: Advanced Features Topic 12: Multithreading Volume II,Chapter 1.

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();

} }}

Page 33: COMP201 Java Programming Part III: Advanced Features Topic 12: Multithreading Volume II,Chapter 1.

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.

Page 34: COMP201 Java Programming Part III: Advanced Features Topic 12: Multithreading Volume II,Chapter 1.

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.

Page 35: COMP201 Java Programming Part III: Advanced Features Topic 12: Multithreading Volume II,Chapter 1.

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

Page 36: COMP201 Java Programming Part III: Advanced Features Topic 12: Multithreading Volume II,Chapter 1.

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

Page 37: COMP201 Java Programming Part III: Advanced Features Topic 12: Multithreading Volume II,Chapter 1.

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

Page 38: COMP201 Java Programming Part III: Advanced Features Topic 12: Multithreading Volume II,Chapter 1.

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!

Page 39: COMP201 Java Programming Part III: Advanced Features Topic 12: Multithreading Volume II,Chapter 1.

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

Page 40: COMP201 Java Programming Part III: Advanced Features Topic 12: Multithreading Volume II,Chapter 1.

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

Page 41: COMP201 Java Programming Part III: Advanced Features Topic 12: Multithreading Volume II,Chapter 1.

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;

Page 42: COMP201 Java Programming Part III: Advanced Features Topic 12: Multithreading Volume II,Chapter 1.

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

Page 43: COMP201 Java Programming Part III: Advanced Features Topic 12: Multithreading Volume II,Chapter 1.

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

Page 44: COMP201 Java Programming Part III: Advanced Features Topic 12: Multithreading Volume II,Chapter 1.

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

Page 45: COMP201 Java Programming Part III: Advanced Features Topic 12: Multithreading Volume II,Chapter 1.

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].

Page 46: COMP201 Java Programming Part III: Advanced Features Topic 12: Multithreading Volume II,Chapter 1.

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

Page 47: COMP201 Java Programming Part III: Advanced Features Topic 12: Multithreading Volume II,Chapter 1.

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

Page 48: COMP201 Java Programming Part III: Advanced Features Topic 12: Multithreading Volume II,Chapter 1.

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.

Page 49: COMP201 Java Programming Part III: Advanced Features Topic 12: Multithreading Volume II,Chapter 1.

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 ();

Page 50: COMP201 Java Programming Part III: Advanced Features Topic 12: Multithreading Volume II,Chapter 1.

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.

Page 51: COMP201 Java Programming Part III: Advanced Features Topic 12: Multithreading Volume II,Chapter 1.

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

Page 52: COMP201 Java Programming Part III: Advanced Features Topic 12: Multithreading Volume II,Chapter 1.

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

Page 53: COMP201 Java Programming Part III: Advanced Features Topic 12: Multithreading Volume II,Chapter 1.

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.

Page 54: COMP201 Java Programming Part III: Advanced Features Topic 12: Multithreading Volume II,Chapter 1.

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.

Page 55: COMP201 Java Programming Part III: Advanced Features Topic 12: Multithreading Volume II,Chapter 1.

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.

Page 56: COMP201 Java Programming Part III: Advanced Features Topic 12: Multithreading Volume II,Chapter 1.

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.

Page 57: COMP201 Java Programming Part III: Advanced Features Topic 12: Multithreading Volume II,Chapter 1.

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.

Page 58: COMP201 Java Programming Part III: Advanced Features Topic 12: Multithreading Volume II,Chapter 1.

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.

Page 59: COMP201 Java Programming Part III: Advanced Features Topic 12: Multithreading Volume II,Chapter 1.

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?

Page 60: COMP201 Java Programming Part III: Advanced Features Topic 12: Multithreading Volume II,Chapter 1.

COMP201 Topic 13 / Slide 60

Synchronization/wait and notify

wait

notifyAll

Page 61: COMP201 Java Programming Part III: Advanced Features Topic 12: Multithreading Volume II,Chapter 1.

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

Page 62: COMP201 Java Programming Part III: Advanced Features Topic 12: Multithreading Volume II,Chapter 1.

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

Page 63: COMP201 Java Programming Part III: Advanced Features Topic 12: Multithreading Volume II,Chapter 1.

COMP201 Topic 13 / Slide 63

DeadlockThe Dining-Philosophers’ Problem

Page 64: COMP201 Java Programming Part III: Advanced Features Topic 12: Multithreading Volume II,Chapter 1.

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.

Page 65: COMP201 Java Programming Part III: Advanced Features Topic 12: Multithreading Volume II,Chapter 1.

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

Page 66: COMP201 Java Programming Part III: Advanced Features Topic 12: Multithreading Volume II,Chapter 1.

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.)

Page 67: COMP201 Java Programming Part III: Advanced Features Topic 12: Multithreading Volume II,Chapter 1.

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.

Page 68: COMP201 Java Programming Part III: Advanced Features Topic 12: Multithreading Volume II,Chapter 1.

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}

Page 69: COMP201 Java Programming Part III: Advanced Features Topic 12: Multithreading Volume II,Chapter 1.

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();

Page 70: COMP201 Java Programming Part III: Advanced Features Topic 12: Multithreading Volume II,Chapter 1.

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

Page 71: COMP201 Java Programming Part III: Advanced Features Topic 12: Multithreading Volume II,Chapter 1.

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.

Page 72: COMP201 Java Programming Part III: Advanced Features Topic 12: Multithreading Volume II,Chapter 1.

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

Page 73: COMP201 Java Programming Part III: Advanced Features Topic 12: Multithreading Volume II,Chapter 1.

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();}}

Page 74: COMP201 Java Programming Part III: Advanced Features Topic 12: Multithreading Volume II,Chapter 1.

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;}

Page 75: COMP201 Java Programming Part III: Advanced Features Topic 12: Multithreading Volume II,Chapter 1.

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;}

Page 76: COMP201 Java Programming Part III: Advanced Features Topic 12: Multithreading Volume II,Chapter 1.

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