28
Practice Session 7 • Synchronization • Liveness Deadlock Starvation Livelock Guarded Methods Model Thread Timing Busy Wait Sleep and Check Wait and Notify

Practice Session 7 Synchronization Liveness Deadlock Starvation Livelock Guarded Methods Model Thread Timing Busy Wait Sleep and Check Wait and Notify

Embed Size (px)

Citation preview

Practice Session 7

• Synchronization• Liveness• Deadlock• Starvation• Livelock

• Guarded Methods Model• Thread Timing

• Busy Wait• Sleep and Check• Wait and Notify

Synchronization

• A mechanism that allows safe access to shared resources.• Java provides 3 ways to define synchronized blocks:

– Synchronized instance method• All the statements in the method become the synchronized block.• All synchronized methods of the same object / synchronized blocks with that object are locked.• The instance object is the lock.

– Synchronized Block• A block of code that is part of a method.• All the statements specified in the parentheses of the synchronized statement become the

synchronized block, • The object specified in the statement is the lock.

Synchronized examples• Synchronized Instance Method:

class Counter { public synchronized void increment() { //this function is locked for an instance of object.

x++;

} }

• Synchronized Statement: class Counter {

Object a = new Object();public synchronized void increment() { //this function is locked for an instance of object.

x++;

}public void increment2() { //this function can be accessed by all threads at any time. //non safe code can be put here

synchronized (a) { //instance of the object is locked when this block is accessed.x++;

} }

}

Example1public class A{

public void fun1(){…}public void fun2(){…}public synchronized void fun3(){….}public synchronized void fun4(){….}

}public class B implements Runnable{

private A a;

B(A a){ this.a = a;}

void run(){1. a.fun1();2. a.fun3();3. synchronized(a){4. a.fun2();5. }

}}

A a = new A();Thread t1 = new Thread(new B(a));Thread t2 = new Thread(new B(a));t1.start();t2.start();

t1

running line 1

running line 2

running line 3,4

done with line 5

t2

can be running any line

running line 1blocked at line: 2, or 3running line 1blocked at line: 2 or 3

can be running any line

Example2public class A{

public void fun1(){…}public void fun2(){…}public synchronized void fun3(){….}public synchronized void fun4(){….}

}public class B implements Runnable{

private A a;

B(A a){ this.a = a;}

void run(){1. a.fun1();2. a.fun3();3. synchronized(a){4. a.fun2();5. }

}}

Thread t1 = new Thread(new B(new A()));Thread t2 = new Thread(new B(new A()));t1.start();t2.start();

t1

running line 1

running line 2

running line 3,4

done with line 5

t2

can be running any line

can be running any line

can be running any line

can be running any line

Example3public class A{

public void fun1(){…}public void fun2(){…}public synchronized void fun3(){….}public synchronized void fun4(){….}

}public class B1 implements Runnable{

private A a;

B(A a){ this.a = a;}

void run(){1. a.fun1();2. a.fun3();3. synchronized(a){4. a.fun2();5. }

}}

A a = new A();Thread t1 = new Thread(new B1(a));Thread t2 = new Thread(new B2(a));t1.start();t2.start();

public class B2 implements Runnable{private A a;

B(A a){ this.a = a;}

void run(){1. a.fun4();2. a.fun1();3. a.fun2();}

}

t1

running line 1

running line 2

running line 3,4

done with line 5

t2

can be running any line

running line: 2, 3blocked at line: 1running line: 2, 3blocked at line: 1can be running any line

Blocking using a Dummy Object

• Used to synchronize code blocks found in different objects of different types.class Counter {

private Object myLock = new Object();public void increment() { //this function can be accessed by all threads at any time. //non safe code can be put here

synchronized (myLock ) { //instance of the object is locked when this block is accessed.x++;

}

}

}

Examplepublic class A implements Runnable{

private Object fLock;

A(Object lock){fLock = lock;}

void run(){<some commands>synchronized(fLock){

<some commands>}<some commands>

}}

public class B implements Runnable{private Object fLock;

B(Object lock){fLock = lock;}

void run(){<some commands>synchronized(fLock){

<some commands>}<some commands>

}}

t1 - > t2 - >t2 - >t2 - >t2 - >

t2 - >

Examplepublic class A implements Runnable{

private Object fLock;

A(Object lock){fLock = lock;}

void run(){<some commands>synchronized(fLock){

<some commands>}<some commands>

}}

public class B implements Runnable{private Object fLock;

B(Object lock){fLock = lock;}

void run(){<some commands>synchronized(fLock){

<some commands>}<some commands>

}}

t1 - >t2 - >t2 - >t2 - >t2 - >

t2 - >

Examplepublic class A implements Runnable{

private Object fLock;

A(Object lock){fLock = lock;}

void run(){<some commands>synchronized(fLock){

<some commands>}<some commands>

}}

public class B implements Runnable{private Object fLock;

B(Object lock){fLock = lock;}

void run(){<some commands>synchronized(fLock){

<some commands>}<some commands>

}}

t1 - >

t2 - >t2 - >

t2 - >

Examplepublic class A implements Runnable{

private Object fLock;

A(Object lock){fLock = lock;}

void run(){<some commands>synchronized(fLock){

<some commands>}<some commands>

}}

public class B implements Runnable{private Object fLock;

B(Object lock){fLock = lock;}

void run(){<some commands>synchronized(fLock){

<some commands>}<some commands>

}}

t1 - >

t2 - >t2 - >t2 - >t2 - >

t2 - >

Good to Know – Class Level Synchronization– Each object can have two locks: an instance lock, and a class lock, and they are two different locks!– All the statements in the method/code block become the synchronized block.– The class itself is the lock.

• Synchronized Class function (static): class Counter {

public static synchronized void increment() { x++; }

} • Synchronized Block:

Synchronized(Counter.class){<commands>

}

Examplepublic class A{

public void fun1(){…}public void fun2(){…}public synchronized void fun3(){….}public synchronized void fun4(){….}public static synchronized void fun5(){…}public static synchronized void fun6(){…}

}

public class B1 implements Runnable{private A a;B(A a){ this.a = a;}void run(){

1. a.fun1();2. a.fun3();3. A.fun5();4. synchronized(a){5. a.fun2();6. }7. synchronized(A.class){8. a.fun4();9. }}

}

Thread t1 = new Thread(new B1(new A()));Thread t2 = new Thread(new B1(new A()));t1.start();t2.start();

t1

running line 1

running line 2

running line 3

running line 4-6

running line 7-9

t2

can be running any line

can be running line: 1,2, 4,5,6Blocked at: 7, 3can be running any line

can be running any line

can be running line: 1,2,4,5,6Blocked at line: 3, 7

Liveness

• Definition:– A concurrent application's ability to execute in a timely manner is

known as its liveness. • Liveness problems:

• Deadlock• Starvation• Livelock

Deadlock• Traffic Jam

• Dining Philosophers (all of them take the left fork at the same time, then try to take the left one).

• Device allocation:– process 1 requests HD and gets it– process 2 requests DVD drive and gets it– process 1 requests DVD drive but is blocked– process 2 requests HD but is blocked

• Infinite wait!

(Code Example - eclipse!)

Deadlock SolutionThread 1acquire Printeracquire Scanneruse printeruse scannerrelease Printerrelease Scanner

Thread 2acquire Scanneracquire Printeruse scanneruse printerrelease Scannerrelease Printer

Thread 1acquire Printeracquire Scanneruse printeruse scannerrelease Printerrelease Scanner

Thread 2acquire Printeracquire Scanneruse printeruse scannerrelease Printerrelease Scanner

Solution?

ResourceOrdering!

All threads must acquire the locks in the same order!

Starvation

• Some threads are waiting forever for resources that are used by other threads.

• Example:– dining philosophers– 2,4 eat always– 1,3,5 never get the chance! 1

2

3

4

5

Starvation

• A task will starve if it ceases to make progress in the presence of others.

• Example:– Priority scheduling

• Each thread has priority level: low, high.• Low priority threads execute only if there are no high priority threads.

– Problem:• High priority threads keep coming.• Low priority threads never get the chance to run!

Livelock

• Threads are unable to make progress although they are not blocked.

• Task enters infinite loop of operations that lead to nothing.• Example:– Lock device 1– Attempt to lock memory resource, fail– Release device 1– Retry

Livelock - Example

• A husband and wife eating at a restaurant• they are sharing a fork. • they won't eat unless they are sure the other one has eaten first. • Result - livelock: – The wife takes the fork,– checks if the husband has eaten, – returns the fork. (same with the husband).

Deadlock, Livelock, Starvation

• Deadlocks/livelocks rarely happen.• Deadlocks/livelocks lead to thread starvation.• Starvation is not limited to deadlocks/livelocks only:– A thread might wait infinitely for a resource to be released, this might

happen when higher priority threads keep getting access to such a resource.

– A thread might not get to run at all due to its low priority.

Guarded Methods Model

• Definition– The guarded method model delays the execution of a thread until a

condition is satisfied.– A thread that is unable to proceed, waits for condition change made

by another thread.• How is it done?– Busy Wait– Sleep and Check– Wait and Notify

Thread Timing

• Running threads in a specified order.• Enforce order within a group of threads.• How?– The group of threads is split into sub groups.– Order of sub groups is enforced.– Only when first sub group of threads finishes running,– the next one is allowed to run.

Thread Timing Example

• Main works through a shared object, called: checkerObject• checkerObject handles the order of thread execution.• Done by assigning numbers for each thread.

• Each thread complying to specific number is allowed to run.• Once all of them are done working• checkerObject increments the number value.

• Example:• Order of execution: {T1, T2, T3} -> {T4, T5} -> {T6}• First group is assigned #1, 2nd group is assigned #2, and the last one is assigned #3.• Using the checkerObject we maintain order of thread execution.

How to check if a thread allowed to run?

• Busy Waiting– Each thread constantly checks whether the condition is met.– Done using a loop.– This results in heavy CPU usage.– Not recommended.– Special cases:

• Waiting time will be very small.• It is critical to instantly react when the condition is met.

• Sleep and Check– Similar to busy wait, but with the addition of sleep interval after each check.– Uses much less CPU cycles.– Disadvantage: delay in reaction when the condition is met.

• Wait and Notify– Requires communication between threads.– A thread waits until some condition occurs. – Some other thread can then notify the waiting thread, to continue its execution– Once the thread is notified, it validates the condition again. This is because multiple threads might be waiting for notification. Examples: Threads01, Threads02, Threads03

Busy Wait Example

public class A implements Runnable{private boolean fShouldRun;A(boolean flag){

fShouldRun = flag;}void run(){

while(!fShouldRun);<some commands>

}}

Sleep & Wait Examplepublic class A implements Runnable{

private boolean fShouldRun;A(boolean flag){ fShouldRun = flag;}void run(){while(!fShouldRun){try{Thread.sleep(100);}catch( InterruptedException e){}<some commands>}

}

Wait & Notify Examplepublic class A implements Runnable{

private boolean fShouldRun;private Object fDummyObject;

A(boolean flag, Object dummyObject){ fShouldRun = flag; fDummyObject = dummyObject;

}void run(){

while(!fShouldRun){try{

fDummyObject.wait(); }catch( InterruptedException e){

}<some commands>

}}

public class B implements Runnable{private Object fDummyObject;

B(Object dummyObject){ fShouldRun = flag; fDummyObject = dummyObject;

}void run(){

<some commands>fDummyObject.notifyAll();

}}