280 likes | 397 Views
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:
E N D
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++; } } }
Example1 A a = new A(); Thread t1 = new Thread(new B(a)); Thread t2 = new Thread(new B(a)); t1.start(); t2.start(); public 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. } } } can be running any line running line 1 blocked at line: 2, or 3 running line 1 blocked at line: 2 or 3 can be running any line
Example2 Thread t1 = new Thread(new B(new A())); Thread t2 = new Thread(new B(new A())); t1.start(); t2.start(); public 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. } } } can be running any line can be running any line can be running any line can be runningany line
Example3 public class B2 implements Runnable{ private A a; B(A a){ this.a = a;} void run(){ 1. a.fun4(); • a.fun1(); • a.fun2(); } } A a = new A(); Thread t1 = new Thread(new B1(a)); Thread t2 = new Thread(new B2(a)); t1.start(); t2.start(); public 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. } } } can be runningany line running line: 2, 3 blocked at line: 1 running line: 2, 3 blocked at line: 1 can be runningany 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++; } } }
Example public class B implements Runnable{ private Object fLock; B(Object lock){fLock = lock;} void run(){ <some commands> synchronized(fLock){ <some commands> } <some commands> } } public class A implements Runnable{ private Object fLock; A(Object lock){fLock = lock;} void run(){ <some commands> synchronized(fLock){ <some commands> } <some commands> } } t1 - > t2 - > t2 - > t2 - > t2 - > t2 - >
Example public class B implements Runnable{ private Object fLock; B(Object lock){fLock = lock;} void run(){ <some commands> synchronized(fLock){ <some commands> } <some commands> } } public class A implements Runnable{ private Object fLock; A(Object lock){fLock = lock;} void run(){ <some commands> synchronized(fLock){ <some commands> } <some commands> } } t2 - > t2 - > t1 - > t2 - > t2 - > t2 - >
Example public class B implements Runnable{ private Object fLock; B(Object lock){fLock = lock;} void run(){ <some commands> synchronized(fLock){ <some commands> } <some commands> } } public class A implements Runnable{ private Object fLock; A(Object lock){fLock = lock;} void run(){ <some commands> synchronized(fLock){ <some commands> } <some commands> } } t2 - > t2 - > t1 - > t2 - >
Example public class B implements Runnable{ private Object fLock; B(Object lock){fLock = lock;} void run(){ <some commands> synchronized(fLock){ <some commands> } <some commands> } } public class A implements Runnable{ private Object fLock; A(Object lock){fLock = lock;} void run(){ <some commands> synchronized(fLock){ <some commands> } <some commands> } } t2 - > t2 - > t2 - > t2 - > t1 - > 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 classitselfis the lock. • Synchronized Class function (static): class Counter { publicstatic synchronized void increment() { x++; } } • Synchronized Block: Synchronized(Counter.class){ <commands> }
Example Thread t1 = new Thread(new B1(new A())); Thread t2 = new Thread(new B1(new A())); t1.start(); t2.start(); public 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(); • a.fun3(); • A.fun5(); 4. synchronized(a){ 5. a.fun2(); • } 7. synchronized(A.class){ 8. a.fun4(); 9. } } } can be running any line can be running any line can be running line: 1,2, 4,5,6 Blocked at: 7, 3 can be runningany line can be running line: 1,2,4,5,6 Blocked 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 Solution Thread 1 acquire Printer acquire Scanner use printer use scanner release Printer release Scanner Thread 2 acquire Scanner acquire Printer use scanner use printer release Scanner release Printer Solution? Resource Ordering! All threads must acquire the locks in the same order! Thread 2 acquire Printer acquire Scanner use printer use scanner release Printer release Scanner Thread 1 acquire Printer acquire Scanner use printer use scanner release Printer release Scanner
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! 3 2 4 1 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 waitsuntil 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 booleanfShouldRun; A(boolean flag){ fShouldRun = flag; } void run(){ while(!fShouldRun); <some commands> } }
Sleep & Wait Example public class A implements Runnable{ private booleanfShouldRun; A(boolean flag){ fShouldRun = flag; } void run(){ while(!fShouldRun){ try{ Thread.sleep(100); }catch( InterruptedException e){ } <some commands> } }
Wait & Notify Example public class A implements Runnable{ private booleanfShouldRun; 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(); } }