Threads
Threads
1
What is a Thread?
A Thread or Thread of execution refers to the execution of a sequential set of instructions.
Multi Threading is the ability to run multiple threads of execution concurrently.
Why multi-thread?
What actually happens on a single processor?
Threads
2
Problems with multithreading
No one thread should disturbs the work of any other thread. Example: Imagine an office - workers function independently and work in parallel except when they need to share office resources/communicate. • Two workers can speak only if one speaks and the other listens • A worker cannot use the copy machine until the machine is free
Multiple threads of a program are much like the workers • For two threads to communicate - one has to talk and the other has to listen • For a thread to use a shared resources, the resource has to be free and ready
Threads
3
Problems with multithreading The Cooperative threading and Preemptive threading model copier
copier C o o p e r a t i v e
start copying
start copying
done copying
start copying
done copying
P r e e m p t i v e
pause copying start copying pause copying restart copying pause copying start copying pause copying
start copying
done copying
Threads
4
How do you make a class run in its own thread? • •
extend Thread, or implement Runnable
Extending Thread public MyThreadedClass extends Thread{ … //instance variables and methods of MyThreadedClass public void run(){ //method inherited and overridden from Thread //the run method is like method main for MyThreadedClass //… } public static void main(){ MyThreadedClass mtc = new MyThreadedClass(); mtc.start(); //inherited from Thread //Never call run - always call start System.out.println(“main done”); } }
4. start() calls run()
2. creates object 3. calls start() 1. main begins
5. new thread of execution for MyThreadedClass
5. prints message
main pausedThreads 4. main starts up
6. main ends time
5
Extending Thread import java.util.*; Points: public class TimePrinter extends Thread{ • thread creation and activation int pauseTime; • sleep() String name; public TimePrinter(int x, String n){ puaseTime = x; name = n; } public void run(){ while (true){ try{ System.out.println(name+”:”+new Date(System.currentTimeMillis())); Thread.sleep(pauseTime); }catch(Exception e){ System.out.println(e); } } } public static void main(String args[]){ TimePrinter tp1 = new TimePrinter(1000, “Fast”); TimePrinter tp2 = new TimePrinter(3000, “slow”); tp1.start(); tp2.start(); System.out.println(“main-bye-bye”); } What’s the downside of extending Thread? }
How many threads do we have?
Threads
6
Implementing Runnable import java.util.*; public class TimePrinter implements Runnable{ int pauseTime; String name; public TimePrinter(int x, String n){ puaseTime = x; name = n; } public void run(){ while (true){ try{ System.out.println(name+”:”+new Date(System.currentTimeMillis())); Thread.sleep(pauseTime); }catch(Exception e){ System.out.println(e); } } } public static void main(String args[]){
Thread t1 = new Thread(new TimePrinter(1000, “Fast”)); Thread t2 = new Thread(TimePrinter(3000, “slow”)); t1.start(); t2.start(); System.out.println(“main-bye-bye”); } } Threads
7
Thread life cycle
born start
ready assigned a processor
yield
IO complete
running
done waiting notify or notifyAll
doing IO
wait sleep
waiting
complete
sleeping
dead
blocked
done sleeping when sleep interval expires OR if interrupted Ref. Fig 15.1 “Life Cycle of a Thread” Java How to Program, 3rd Ed. Deitel & Deitel
Threads
8
Synchronizing execution between two threads Understanding the problem Assume a simple BankAccount class.
makes a withdrawal
checks balance
public class BankAccount{ String holderName; float amount; public Account(String n, float a){ holderName = n; amount = a; } public void deposit(float a){ amount = amount + a; } public void withdraw(float a){ amount = amount - a; } public float checkBalance(){ return amount; } }
makes a direct-deposit
electronic transfer
Electronic pay ATM transaction
What would happen if these actions could happen in parallel? Would the Threads account balance be correctly maintained?
9
Synchronizing execution between two threads Solution - To “lock” methods so that only one thread can execute that method public class BankAccount{ String holderName; float amount; public Account(String n, float a){ holderName = n; amount = a; }
paused and waiting their turn
public synchronized void deposit(float a){ amount = amount + a; } public synchronized void withdraw(float a){ amount = amount - a; } public float checkBalance(){ return amount; }
Locked Method
}
Notice: checkBalance() not synchronized
Threads
one thread allowed through at a time
10
Synchronizing execution between two threads An object with a synchronized method will only allow one thread at a time to execute a synchronized method. Such an object is called a Monitor If there are many synchronized methods only one synchronized method may be active on an object at once; all other threads attempting to invoke synchronized methods must wait. Assume thread1 and thread2 both want to run a synchronized method Thread 1 1. gets lock on Monitor 2. starts running synchronized method
Thread 2 1. Enters wait state, waiting on Thread 1 to finish
Run State
1. done running synchronized method 2. issues a “notify” message
Ready State Wait State
Cannot predict who will start, Thread1 or 2
Hears the “notify” message and enters the ready state
Thread 2 can only run unsynchronized methods of the Monitor while Thread 1 is running a synchronized method. Threads
11
The (classic) producer-consumer example 3-classes: The “producer” produces an integer to be consumed by the “consumer”. The produced value is held in a common shared cell. Rules: Producer
Consumer integer
• Consumer may consume an integer once • Consumer may not consume until the producer has produced
How do we make 2-objects share? public class ProducerConsumerExample{ public static void main(String[] args){ SharedCell sc = new SharedCell(); Producer p = new Producer(sc); Consumer c = new Consumer(sc); Thread t1 = new Thread(p); Thread t2 = new Thread(c); t1.start(); t2.start(); } }
Threads
12
The producer-consumer example public class SharedCell{ private int shared = -1; public void set(int i){ System.out.println(“producer producing “+ i); shared = i; } public int get(){ System.out.println(“Consumer consuming “+shared); return shared; } } public class Producer implements Runnable{ private SharedCell shared; public Producer(SharedCell sc){shared = sc;} public void run(){ int sum=0; for(int count=0; count<10; count++){ //sleep for random amount try{ Thread.sleep((int)(Math.random()*3000)); catch(InterruptedException e){ System.err.println(e.toString()); } shared.set(count); sum += count; } System.out.println(“Producer, produced “+sum); Threads } }
13
The producer-consumer example public class Consumer implements Runnable{ private SharedCell shared; public Consumer (SharedCell sc){shared = sc;} public void run(){ int val, sum=0; do{ //sleep for random amount try{ Thread.sleep((int)(Math.random()*3000)); catch(InterruptedException e){ System.err.println(e.toString()); } val = shared.get(); sum += val; }while(val != 9); System.err.println(“Consumer, consumed ”+ sum); } }
Notice what happens when you run this! Consumer consumes way more than the producer produces
Threads
14
The producer-consumer example public class SharedCellSynchronizedI{ private int shared = -1; public synchronized void set(int i){ System.out.println(“producer producing “+ i); shared = i; } public synchronized int get(){ System.out.println(“Consumer consuming “+shared); return shared; } }
Still does not work! •How to prevent the consumer from consuming more than once? •How to prevent the producer from producing more than once? •Observe unpredictable nature of which thread will run after they both enter the “ready” state.
Do we need to synchronize SharedCell methods? Threads
15
The producer-consumer example Create a boolean variable consumerHasConsumed Initialize consumerHasConsumed to true Producer (set())
Consumer (get())
If (consumerHasComsumed is false) producer will “wait” else producer will produce set consumerHasConsumed to false
If (consumerHasConsumed is true) consumer will “wait” else consumer will consume set consumerHasConsumed to true
public class SharedCellSynchronizedII{ private int shared = -1; boolean consumerHasConsumed public synchronized void set(int i){ while (consumerHasConsumed == false){ //consumer has yet to consume - so wait. try{ wait(); //give up control }catch(InterruptedException e){ e.printStackTrace(); } } System.out.println("producer producing "+i); shared = i; consumerHasConsumed = false; notify(); //signal the waiting //consumer to get ready }
public synchronized int get(){ while(consumerHasConsumed ){ //producer has yet to produce - so wait try{ wait(); //give up control }catch(InterruptedException e){ e.printStackTrace(); } } System.out.println("Consumer consuming "+shared); consumerHasConsumed = true; notify(); //signal the waiting producer //to get ready return shared; }
Threads
16
The producer-consumer example
public class ProducerConsumerFinal{ public static void main(String[] args){ SharedCell sc = new SharedCellSynchronizedII(); Producer p = new Producer(sc); Consumer c = new Consumer(sc); Thread t1 = new Thread(p); Thread t2 = new Thread(c); t1.start(); t2.start(); } }
Summary: • Two independent threads work with a common object • Both threads “own” the common object (not threaded) • Because of method synchronization only one thread can execute on the object at a time • Both threads voluntarily give up owner ship by “waiting” • Common object coordinates the common activity.
Threads
17
wait verses sleep - which to use? What’s the difference?
• A waiting thread can be activated using a notify command. •Sleeping threads sleep the whole duration or till its interrupted. Use sleep/interrupt if you want to control when a thread runs. • Both sleep() and wait() give up contending for the CPU, even if the thread is in a synchronized method. • sleep() DOES NOT give up ownership of monitors, wait() does. Question: What would have happened if we had used sleep() instead of wait() in example? • To use wait(), the current thread must own the objects monitor. Huh?
Threads
18
Modeling a Train, track and a crossing using threads Classes and interactions: Train (threaded) - simply travels along a track Track - not threaded has a crossing, and keeps track of the train position Crossing arm (threaded) - lowers and raises the arm based on a signal from the track
The Train: public class Train implements Runnable{ Track track; … public void run(){ while (!track.atStation()){ track.travelAMile(); sleep a while to model travel time } } } Threads
19
Modeling a Train, track and a crossing using threads The track (not threaded): public class Track{ int trainPosition; int STATIONPOSITION; int CROSSINGPOSITION; CrossingArm ca; … public void travelAMile(){ trainPosition--; if (trainPosition == CROSSINGPOSITION - 1) wake up the crossing arm else if (trainPosition == CROSSINGPOSITION + 1) wake up the crossing arm else if (trainPosition == STATIONPOSITION){ set variables to terminate the arm wake up the crossing arm so it can terminate } } public boolean isAtStation(){ return (trainPosition == STATIONPOSITION); } }
Threads
20
Modeling a Train, track and a crossing using threads public CrossingArm implements Runnable{ boolean alive = true; … public void run(){ while (alive){ sleep till I am awoken … if (awoken){ if (alive) && (arm is up) else if (alive) } } }
lower arm raise arm
public void destroyArm(){ alive = false; }
Threads
21
Deadlocking Happens when there are: • at two shared resources • two threads that both need both resources to complete a task.
What happens? • Thread 1 gets the lock for resource 1 and waits on resource 2 • Thread 2 gets the lock for resource 2 and waits on 1 • Neither thread now can continue because the other thread has a critical lock
Classic Example: • Dinners problem • Imagine two people at dinner having to share a knife and fork • Person 1 has gets the knife and person 2 the fork - now neither can eat. (more general problem called Dinning philosophers problem…)
Threads
22
Deadlocking - what’s the solution? Number the resources 1 ,.., n Let each thread try to get resource 1 first. unsuccessful
successful
Enters wait state
Gets the rest of the resources (2…n)
Why does this work? • Because no thread will have resource i > 1 unless it has resource 1. • If a thread has resource 1, then it is guaranteed to get resource 2…n also.
Threads
23