internet software development more stuff on threads paul krause

37
Internet Software Internet Software Development Development More stuff on Threads More stuff on Threads Paul Krause Paul Krause

Upload: melvin-mills

Post on 11-Jan-2016

214 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Internet Software Development More stuff on Threads Paul Krause

Internet Software Internet Software DevelopmentDevelopment

More stuff on ThreadsMore stuff on Threads

Paul KrausePaul Krause

Page 2: Internet Software Development More stuff on Threads Paul Krause

Lecture 12 - Lecture 12 -

ContentsContents Basics of threads and synchronizationBasics of threads and synchronization Waiting - releasing locksWaiting - releasing locks Collection Plate exampleCollection Plate example Choices when pausing executionChoices when pausing execution Ice Cream ExampleIce Cream Example Notify versus NotifyAllNotify versus NotifyAll

Page 3: Internet Software Development More stuff on Threads Paul Krause

Quick ReminderQuick Reminder

User requests document is printed and

saved

Word processor

spools print job

Word processor

starts saving to hard drive

User requests document is printed and

saved

Page 4: Internet Software Development More stuff on Threads Paul Krause

A Better SolutionA Better Solution

User requests document is printed and

saved

Spawn threads to print and

save

Main thread waits until

other threads are complete

User gets control ready

for next operation

Thread starts spooling print

job

Thread starts saving

document to hard drive

Page 5: Internet Software Development More stuff on Threads Paul Krause

Basic conceptsBasic concepts

Synchronization enables a Java object to Synchronization enables a Java object to be locked for exclusive use by a threadbe locked for exclusive use by a thread

A locked object is inaccessible to any A locked object is inaccessible to any thread other than the one that locked itthread other than the one that locked it So long as the other threads honour thisSo long as the other threads honour this

Each object can keep track of the other Each object can keep track of the other threads that want exclusive access to itthreads that want exclusive access to it

How to keep threads fighting over limited How to keep threads fighting over limited toys!toys!

Page 6: Internet Software Development More stuff on Threads Paul Krause

WaitingWaiting

This is This is notnot just a matter of notifying the just a matter of notifying the JVM it can (but doesn’t have to!) provide JVM it can (but doesn’t have to!) provide resource to other threadsresource to other threads As with As with Thread.yieldThread.yield or or Thread.sleepThread.sleep

Calling Calling myObject.waitmyObject.wait will release will release myObjectmyObject’s lock’s lock

Waiting is the process of getting Waiting is the process of getting (completely) out of the way when you can’t (completely) out of the way when you can’t be productivebe productive

Page 7: Internet Software Development More stuff on Threads Paul Krause

CollectionPlate exampleCollectionPlate example

Minister passes around a collection plateMinister passes around a collection plate He He waitswaits until the collection has exceeded until the collection has exceeded

a certain amounta certain amount While he is waiting, other people can While he is waiting, other people can

modify the state of the collection platemodify the state of the collection plate By adding money to itBy adding money to it

Once the total collected exceeds a certain Once the total collected exceeds a certain amount, the Minister takes back the plateamount, the Minister takes back the plate

Page 8: Internet Software Development More stuff on Threads Paul Krause

Structure of Minister ClassStructure of Minister Class

public class Minister {public class Minister {

private CollectionPlate collectionPlate private CollectionPlate collectionPlate

= new CollectionPlate();= new CollectionPlate();

……

private class CollectionAcceptor extends Thread {private class CollectionAcceptor extends Thread {

… … }}

private class CollectionChecker extends Thread {private class CollectionChecker extends Thread {

… … }}

}}

Page 9: Internet Software Development More stuff on Threads Paul Krause

CollectionPlateCollectionPlate

We will lock the instance of CollectionPlate We will lock the instance of CollectionPlate whenever we access or modify its statewhenever we access or modify its state

private class CollectionPlate {private class CollectionPlate {

int amount = 0;int amount = 0;

}}

Page 10: Internet Software Development More stuff on Threads Paul Krause

main methodmain method

Start off a thread that is going to monitor Start off a thread that is going to monitor the state of the collectionPlatethe state of the collectionPlate

minister.new CollectionChecker().start();minister.new CollectionChecker().start();

Within the run method of the Within the run method of the CollectionChecker, weCollectionChecker, we Obtain the lock on collectionPlateObtain the lock on collectionPlate If the amount on the collectionPlate is less If the amount on the collectionPlate is less

than 100 we temporarily release the lock until than 100 we temporarily release the lock until we are notified by another thread of a changewe are notified by another thread of a change

Page 11: Internet Software Development More stuff on Threads Paul Krause

CollectionChecker’s run()CollectionChecker’s run() synchronized (collectionPlate) {synchronized (collectionPlate) { while (collectionPlate.amount < 100) {while (collectionPlate.amount < 100) { try {try { System.out.println("Waiting");System.out.println("Waiting"); collectionPlate.wait();collectionPlate.wait(); }} catch (InterruptedException ie) {catch (InterruptedException ie) { ie.printStackTrace();ie.printStackTrace(); }} }} // getting past the while statement means that the // getting past the while statement means that the // contribution goal has been met// contribution goal has been met System.out.println("Thank you!");System.out.println("Thank you!"); }}

Page 12: Internet Software Development More stuff on Threads Paul Krause

More detailMore detail

The CollectionChecker The CollectionChecker mustmust have the lock for have the lock for collectionPlate before it calls wait() on itcollectionPlate before it calls wait() on it

The CollectionChecker cannot proceed if there is The CollectionChecker cannot proceed if there is less than 100 units on the plateless than 100 units on the plate

So theCollectionChecker waits by releasing the So theCollectionChecker waits by releasing the lock on the collectionPlate and waiting until lock on the collectionPlate and waiting until another thread notifies it of a change in state to another thread notifies it of a change in state to the latterthe latter

If the amount is still < 100 it waits some more. If the amount is still < 100 it waits some more. Otherwise it says “Thank you” and terminatesOtherwise it says “Thank you” and terminates

Page 13: Internet Software Development More stuff on Threads Paul Krause

What happens during a waitWhat happens during a wait

In the “Minister” case, several threads have In the “Minister” case, several threads have been started up that can accept been started up that can accept contributions:contributions:

for (int i = 0; i < 6; i++ ) {for (int i = 0; i < 6; i++ ) {

minister.new CollectionAcceptor(20).start();minister.new CollectionAcceptor(20).start();

}}

In turn, each will claim the lock on the In turn, each will claim the lock on the collectionPlate, add $20 and then notify the collectionPlate, add $20 and then notify the ministrr when it has finishedministrr when it has finished

Page 14: Internet Software Development More stuff on Threads Paul Krause

CollectionAcceptor’s run()CollectionAcceptor’s run()

synchronized (collectionPlate) {synchronized (collectionPlate) {

int amount = collectionPlate.amount + int amount = collectionPlate.amount +

contribution;contribution;

String msg = "Contributing: current String msg = "Contributing: current

amount: " + amount: " + amount;amount;

System.out.println(msg);System.out.println(msg);

collectionPlate.amount = amount;collectionPlate.amount = amount;

collectionPlate.notify();collectionPlate.notify();

}}

Page 15: Internet Software Development More stuff on Threads Paul Krause

The resultThe result

In turn (why?) each instance of In turn (why?) each instance of CollectionAcceptor obtains the lock on CollectionAcceptor obtains the lock on collectionPlatecollectionPlate

$20 is then added to the collectionPlate $20 is then added to the collectionPlate and the waiting class is notified when the and the waiting class is notified when the lock is released againlock is released again

The CollectionAcceptor (“minister”) can The CollectionAcceptor (“minister”) can resume execution and check the contents resume execution and check the contents of the collectionPlateof the collectionPlate

Page 16: Internet Software Development More stuff on Threads Paul Krause

An example runAn example run

run-single:run-single:WaitingWaitingContributing: current amount: 20Contributing: current amount: 20WaitingWaitingContributing: current amount: 40Contributing: current amount: 40WaitingWaitingContributing: current amount: 60Contributing: current amount: 60WaitingWaitingContributing: current amount: 80Contributing: current amount: 80WaitingWaitingContributing: current amount: 100Contributing: current amount: 100Thank you!Thank you!Contributing: current amount: 120Contributing: current amount: 120

Page 17: Internet Software Development More stuff on Threads Paul Krause

In GeneralIn General

If If myObject.wait()myObject.wait() is called by is called by threadAthreadA, , then:then: threadAthreadA temporarily releases the lock on temporarily releases the lock on myObjectmyObject Execution of Execution of threadAthreadA is suspended is suspended threadA registers its interest in being notified after threadA registers its interest in being notified after

another thread has modified another thread has modified myObjectmyObject Once notified, Once notified, threadAthreadA can resume execution can resume execution

having recovered the lock on having recovered the lock on myObjectmyObject It is the designer’s responsibility to ensure It is the designer’s responsibility to ensure

waiting objects are notifiedwaiting objects are notified

Page 18: Internet Software Development More stuff on Threads Paul Krause

Pausing executionPausing execution

Maintain current locksMaintain current locks Waiting for some event to occur, before Waiting for some event to occur, before

completing the process of accessing or completing the process of accessing or modifying a resourcemodifying a resource

Release current locksRelease current locks Having completed business with a resource, Having completed business with a resource,

this pause means the thread has finished its this pause means the thread has finished its work for nowwork for now

Page 19: Internet Software Development More stuff on Threads Paul Krause

Other fun things with threads!Other fun things with threads!

YieldingYielding ““Politely offering up your place the the queue”Politely offering up your place the the queue” Does not release locksDoes not release locks

BlockingBlocking A thread will block while it is waiting for a lockA thread will block while it is waiting for a lock The JVM will automatically tranisition it to The JVM will automatically tranisition it to

Runnable when the lock becomes availableRunnable when the lock becomes available SleepingSleeping

Waits Waits at leastat least as long as the specified time as long as the specified time

Page 20: Internet Software Development More stuff on Threads Paul Krause

Ice-cream man exampleIce-cream man example

We create a number of Children as customers of We create a number of Children as customers of an IceCream manan IceCream man

Each Child has an IceCreamDish that should be Each Child has an IceCreamDish that should be filled completely before the IceCream man filled completely before the IceCream man serves another customerserves another customer

In the the application, the instance of In the the application, the instance of IceCreamMan is declared static to ensure there IceCreamMan is declared static to ensure there is only one instance (is there another way of is only one instance (is there another way of doing this?)doing this?)

The IceCreamMan’s thread is set as a “daemon” The IceCreamMan’s thread is set as a “daemon” thread - So?thread - So?

Page 21: Internet Software Development More stuff on Threads Paul Krause

Basic outlineBasic outline

Start the IceCreamMan on a new threadStart the IceCreamMan on a new thread Start three instances of Child, each on Start three instances of Child, each on

their own threadtheir own thread Each child will obtain a dish of ice cream Each child will obtain a dish of ice cream

and eat itand eat it Once all three children have eaten their Once all three children have eaten their

ice cream, the main thread prints out a ice cream, the main thread prints out a message and terminatesmessage and terminates What about iceCreamMan?What about iceCreamMan?

Page 22: Internet Software Development More stuff on Threads Paul Krause

Starting the iceCreamManStarting the iceCreamMan

Remember iceCreamMan = new Remember iceCreamMan = new IceCreamMan() is a static property of Chil\IceCreamMan() is a static property of Chil\ Hence (as far as Children are concerned) Hence (as far as Children are concerned)

there is only one iceCreamManthere is only one iceCreamMan In the main method:In the main method:

iceCreamMan.setDaemon(true);iceCreamMan.setDaemon(true);

iceCreamMan.start();iceCreamMan.start();

Page 23: Internet Software Development More stuff on Threads Paul Krause

Getting the children goingGetting the children going

String[] names = {"Ricardo", "Paolo", "Maria"};String[] names = {"Ricardo", "Paolo", "Maria"};

Thread[] children = new Thread[names.length];Thread[] children = new Thread[names.length];

// create some child objects// create some child objects

// create a thread for each child// create a thread for each child

// get the Child threads started// get the Child threads started

int counter = -1;int counter = -1;

for (String name : names) {for (String name : names) {

Child child = new Child(name);Child child = new Child(name);

children[++counter] = new Thread(child);children[++counter] = new Thread(child);

children[counter].start();children[counter].start();

}}

Page 24: Internet Software Development More stuff on Threads Paul Krause

What’s the iceCreamMan What’s the iceCreamMan doing?doing?

The iceCreamMan has a list of The iceCreamMan has a list of IceCreamDishes:IceCreamDishes:

private List<IceCreamDish> dishes private List<IceCreamDish> dishes

= new ArrayList<IceCreamDish> = new ArrayList<IceCreamDish> ();();

If the list is not empty, he serves some ice If the list is not empty, he serves some ice cream, otherwise he sleeps for a bit to cream, otherwise he sleeps for a bit to give the children a chance to add dishesgive the children a chance to add dishes

Page 25: Internet Software Development More stuff on Threads Paul Krause

iceCreamMan.run()iceCreamMan.run()public void run() {public void run() { while (true) {while (true) { if (!dishes.isEmpty()) {if (!dishes.isEmpty()) {

serveIceCream();serveIceCream(); }} elseelse {{ try {try {

sleep(1000);sleep(1000); }} catch(InterruptedException ie) {catch(InterruptedException ie) { ie.printStackTrace();ie.printStackTrace(); }} }} }}

}}

Page 26: Internet Software Development More stuff on Threads Paul Krause

The story so farThe story so far

The iceCreamMan is waiting for some The iceCreamMan is waiting for some dishes to filldishes to fill

Three children have been started, so what Three children have been started, so what are they doing?are they doing?

Child.run()Child.run()// add myDish to iceCreamMan.dishes// add myDish to iceCreamMan.dishes

iceCreamMan.requestIceCream(myDish);iceCreamMan.requestIceCream(myDish);

// now try to eat myDish of ice cream// now try to eat myDish of ice cream

eatIceCream();eatIceCream();

Page 27: Internet Software Development More stuff on Threads Paul Krause

Eating iceCreamEating iceCream

public void eatIceCream() {public void eatIceCream() {synchronized(myDish) {synchronized(myDish) {

while (myDish.readyToEat == false) {while (myDish.readyToEat == false) {try {try {

System.out.println(name + msg);System.out.println(name + msg);myDish.wait();myDish.wait();

}} catch (InterruptedException ie) {catch (InterruptedException ie) { ie.printStackTrace();ie.printStackTrace(); }} }} myDish.readyToEat = false;myDish.readyToEat = false; }} System.out.println(name + " yum");System.out.println(name + " yum");

}}

Page 28: Internet Software Development More stuff on Threads Paul Krause

So?So?

The Child “owns” the lock on its iceCreamDishThe Child “owns” the lock on its iceCreamDish If the iceCreamDish is not ready to eat, the Child If the iceCreamDish is not ready to eat, the Child

releases the lock and waits to be notified when it releases the lock and waits to be notified when it is fullis full

Note the use of a “while” loop, and not an “if” Note the use of a “while” loop, and not an “if” statement. statement. It is possible that the Child thread could wake up It is possible that the Child thread could wake up

before it is notified. By using a while loop, the guard before it is notified. By using a while loop, the guard will be checked again if such a “spurious wake up” will be checked again if such a “spurious wake up” occursoccurs

Page 29: Internet Software Development More stuff on Threads Paul Krause

IceCreamMan.serveIceCreamIceCreamMan.serveIceCream

private void serveIceCream() {private void serveIceCream() {// get an ice cream dish// get an ice cream dishIceCreamDish currentDish = dishes.get(0);IceCreamDish currentDish = dishes.get(0);

synchronized (currentDish) {synchronized (currentDish) {

currentDish.readyToEat = true;currentDish.readyToEat = true;// notify the dish's owner that the dish is ready// notify the dish's owner that the dish is ready

currentDish.notify();currentDish.notify();}}

// remove the dish from the queue of dishes// remove the dish from the queue of dishesdishes.remove(currentDish);dishes.remove(currentDish);

}}

Page 30: Internet Software Development More stuff on Threads Paul Krause

NoteNote

Correct functioning requires both the writer Correct functioning requires both the writer of Child and the writer of IceCreamMan to of Child and the writer of IceCreamMan to synchronise on IceCreamDishes.synchronise on IceCreamDishes.

There is nothing here that There is nothing here that forcesforces a Child to a Child to synchronize.synchronize. But if she doesn’t, then she may get a half-full But if she doesn’t, then she may get a half-full

or even empty IceCreamDishor even empty IceCreamDish

Page 31: Internet Software Development More stuff on Threads Paul Krause

notify() vs. notifyAll()notify() vs. notifyAll()

In the previous examples, we only had one In the previous examples, we only had one thread waiting for the lock on an object at thread waiting for the lock on an object at a timea time

We used We used notify()notify() to inform the JVM to inform the JVM that when lock was available and the that when lock was available and the waiting thread could resumewaiting thread could resume

In general, there could be several threads In general, there could be several threads waitingwaiting notifyAll()notifyAll() might be more appropriate might be more appropriate

Page 32: Internet Software Development More stuff on Threads Paul Krause

More in More in wait()wait()

Following a Following a wait(myObject)wait(myObject) invocation: invocation: The current thread is blockedThe current thread is blocked

Unless the current thread has been Unless the current thread has been interrupted, in which case the method exits interrupted, in which case the method exits throwing an throwing an InterruptedExceptionInterruptedException..

The thread is placed in an internal “wait The thread is placed in an internal “wait set” associated with set” associated with myObjectmyObject

The lock on The lock on myObjectmyObject is released is released But But allall other locks are retained other locks are retained

Page 33: Internet Software Development More stuff on Threads Paul Krause

notify()notify()

Following a Following a myObject.notify()myObject.notify() invocation:invocation:

If one exists, then an If one exists, then an arbitrarilyarbitrarily chosen chosen thread thread TT is removed from the wait set is removed from the wait set associated with associated with myObjectmyObject

TT must re-obtain the lock on myObject must re-obtain the lock on myObject It will be blocked until it does soIt will be blocked until it does so

TT will then resume from the point of its wait will then resume from the point of its wait

Page 34: Internet Software Development More stuff on Threads Paul Krause

myObject.notifyAll()myObject.notifyAll()

AllAll threads in the wait set for threads in the wait set for myObject myObject are removedare removed

But they must wait in turn for the But they must wait in turn for the synchronization lock on synchronization lock on myObjectmyObject

So they will continue one at a time (at So they will continue one at a time (at least until each respective thread releases least until each respective thread releases the lock)the lock)

Page 35: Internet Software Development More stuff on Threads Paul Krause

NotifyVersusNotifyAll.javaNotifyVersusNotifyAll.java

We will run the program first using We will run the program first using notify()notify() in the main method and then in the main method and then again using again using notifyAll()notifyAll()

Page 36: Internet Software Development More stuff on Threads Paul Krause

Usage guidelinesUsage guidelines

Only use Only use notify()notify() if you are if you are suresure that that the thread that will be notified will be able the thread that will be notified will be able to use the notificationto use the notification Note that in general you will not know which Note that in general you will not know which

thread will be notified by the JVMthread will be notified by the JVM If multiple threads are waiting on one If multiple threads are waiting on one

event, but with different conditions to event, but with different conditions to meet, then best to use meet, then best to use notifyAll()notifyAll()

Page 37: Internet Software Development More stuff on Threads Paul Krause

Simple exampleSimple example

Producer threadProducer threadsynchronized(lock) {synchronized(lock) {

value = Math.random();value = Math.random();lock.notifyAll();lock.notifyAll();

}}

Consumer Thread 1Consumer Thread 1synchronized(lock) {synchronized(lock) {

While (value < 0.5) { lock.wait(); }While (value < 0.5) { lock.wait(); }}}

Consumer Thread 2Consumer Thread 2synchronized(lock) {synchronized(lock) {

While (value >= 0.5) { lock.wait(); }While (value >= 0.5) { lock.wait(); }}}