640 likes | 656 Views
Counting Semaphore Implementation in Java. CS598 – Concurrent Programming. Kasturi Kallakuri Cindy Mayo 21 August 2002. “Alfonse, Wait Here for My Signal!”. Author: Stephen J. Hartley Original presentation: ACM-SIGCSE March 1999 New Orleans, Louisiana. 1 Java is Multithreaded.
E N D
Counting SemaphoreImplementation in Java CS598 – Concurrent Programming Kasturi Kallakuri Cindy Mayo 21 August 2002
“Alfonse, Wait Herefor My Signal!” Author: Stephen J. Hartley Original presentation: ACM-SIGCSE March 1999 New Orleans, Louisiana
1 Java is Multithreaded • The Java Virtual Machine can support many threads of execution at a time • A thread is a separate flow of control within a program • Each thread has its own local variables and lifetime
1 Java is Multithreaded • All threads within a program share the same address space • Thread is represented by the Java Thread class • Threads can be synchronized with other threads in same process
1.1 A Multithreaded Program P R O G R A M Threads HotJava Web Browser is an example of a multithread Java application
1.2 Thread Creation • Implement the Runnable Interface • Subclass (extend) the Thread class
1.2.1 Implementing Runnable class HelloRunnable implements Runnable{ public void run() { System.out.println(“Hello World!”);} } HelloRunnable hr = new HelloRunnable(); Thread hThread = new Thread(hr); hThread.start()
1.2.2 Subclassing Thread class HelloThread extends Thread{ public void run( { System.out.println(“HelloWorld!”); } } HelloThread hThread = new HelloThread(); hThread.start()
running blocked sleeping waiting ready dead born 1.3 Life Cycle of a Thread start() notify() notifyAll() I/O completion quantum expiration “yield” interrupt dispatch issue I/O request wait() complete sleep() sleep interval expires
1.4 Thread Priorities • By default, all threads have equal priority • setPriority() can be used to change the default priority • Java implements MIN_PRIORITY (0) and MAX_PRIORITY (10) • Microsoft’s JVM utilizes time slicing • Solaris’ JVM does not
2 Object Locks • Every Java Object has a lock, which is implemented as a binary semaphore • Java supports mutual exclusion through the synchronized keyword • Object locks may be class locks or class instance locks.
2 Object Locks • Java does not provide a way to perform separate locking and unlocking functions • lock() and unlock() are implicitly performed by high-level constructs that arrange ways to pair such actions correctly • The JVM provides separate monitorenter and monitorexit instructions that implement the lock and unlock actions
2.1 Mutual Exclusion • Synchronized blocks • Synchronized methods
2.1.1 Synchronized block • Acquires the object lock before executing the body of the synchronized block • After execution of the block, unlocks the lock • Syntax: Object obj = new Object(); synchronized (obj) { // critical section }
2.1.1 Synchronized block class Update { private int data = 0; public void increment(){ synchronized(this) { //lock the object data++; } }//end of increment } //end of class
2.1.2 Synchronized method • Automatically performs lock action when invoked • After execution of the method’sbody,unlock action is automatically performed on same lock • Syntax: Object obj = new obj();//methods use synchronized type method(…){ //body of method }
2.1.2 Synchronized method • bump() uses an instance lock (this) • classBump() uses the class lock class Test { int count; static int classCount; synchronized void bump() { count++; } static synchronized void classBump() { classCount++; } }
2.2 ConditionalSynchronization • Waiting process should leave the semaphore but not exit the method • Leaving the object instance releases the lock • Instances need back porch where waiters leave and not exit the instance. [wait set] • There is only one wait set per class instance
2.2 Conditional Synchronization • Object method wait() blocks calling thread in wait set. • Object method notify() unblocks a thread if any in the wait set • Object method notifyAll() unblocks all threads in the wait set.
2.3 Deadlock • Java does not prevent, nor require detection of deadlock conditions • Programs where threads hold locks on multiple objects should use conventional techniques for avoiding deadlock • Create higher level locking primitives that cannot deadlock, if necessary
2.3.1 Mutex behaviour • Mutex unblocking is arbitary • Thread priority is ignored • Thread starvation is possible • Mutex locking is re-entrant • A thread can relock any mutex it holds
2.3.2 Interference • Interference with conditional synchronization • Unblocked thread may not immediately regain the mutex • The signaled condition may no longer be true when it does
2.4 Points to Remember • The acquisition and release of locks is done automatically and atomically by the Java Virtual Machine (JVM), which guarantees that: • Race conditions cannot occur • Data integrity is ensured Mutex behaviour needs to be worked around
3 Java Monitors • Monitors are a data abstract mechanism • Monitors encapsulate data without external access and references outside of the monitor are blocked • Monitors contain variables that store the object’s state and procedures that implement operations on the object
3 Java Monitors • Mutual exclusion is provided implicitly by ensuring that procedures in the same monitor are not executed concurrently • Condition synchronization is provided explicitly by condition variables
3.1 Java Monitor Structure class Monitor { private .. //data fields Monitor(..){…} //constructor synchronized type method1(){ notifyAll(); while ( !condition ) try { wait(); } catch(InterruptedException e){} notifyAll(); } Note: Monitors are compile time entities
3.2 Concurrency Control • Mutual Exclusion • Conditional Synchronization
3.2.1 Mutual Exclusion • A monitor procedure is called by an external process • At most, one instance of monitor procedure may be active at a time • Only one thread at a time is allowed inside the monitor
3.2.1 Mutual Exclusion • Monitor entries are (java) synchronized always. • Monitor procedures by definition execute with mutual exclusion • It is up to the language and operating system to provide mutual exclusion
3.2.2 Condition Synchronization • A condition variable is used to delay a process that cannot safely continue executing until the monitor’s state satisfies some Boolean condition • There may be many condition variables per monitor • Monitor’s back porch
3.2.2 Condition Synchronization • A process queries the state of a condition variable by calling empty() • A process blocks on a condition variable by calling wait() • Processes blocked on a condition variable are awakened by a call to signal()
Condition variable queue Executing in monitor Entry queue 3.3 Signal and Continue Signal and continue wait() monitor free call return
3.3 Signal and Continue • Signal and continue is non preemptive • Condition variable release is FIFO • Relation between signaled and signaler: • Signaled jumps to the front of the entry queue signaler continues
3.4 Perils of Monitors • The thread blocked longest on a monitor synchronized method call is not guaranteed to be next thread to acquire the monitor lock when the monitor lock is released
3.4 Perils of Monitors • The thread blocked the longest in a wait() call is not guaranteed to be the one removed from the wait set when a notify() call is made • Typically, FIFO is used to determine who gets control (JVM/platform specific)
3.4 Perils of Monitors • A thread waiting for the monitor lock to execute a monitor synchronized method might get the lock before a signaled thread reacquires the lock even if the notify occurred earlier than the monitor method call • A thread should always recheck its wait condition when signaled
3.4 Perils of Monitors • The while construct is preferred over the if construct while ( !condition ) wait(); notifyAll();
3.4 Perils of Monitors • Each monitor has a single, nameless condition variable • Cannot specify which of the waiting threads should be released by a notify() call • May need to use notifyAll() to awaken all threads and allow contention
3.4 Perils of Monitors • sleep(), join(), and wait() throw InterruptedException • No exception is thrown if a thread is interrupted while blocked • An exception is thrown by wait() if a thread that has been notified is interrupted while waiting to reacquire the monitor lock
3.4 Perils of Monitors • Ignoring InterruptedException with an empty catch block can be acceptable in a while loop while ( !condition ) try { wait(); } catch (InterruptedException e) {} • Must be using notifyAll()
3.4 Perils of Monitors • Cannot ignore InterruptedException when using an if construct if ( !condition ) try { wait(); } catch (InterruptedException e) {} • Notification slip
3.4 Perils of Monitors • It is desirable to have the containing method throw the exception back to the calling function so that the calling function knows that an exception has actually occurred
4 Counting Semaphores • V() operation if threads blocked in P(), unblock one else increment semaphore value • P() operation if semaphore value is 0 block semaphore else decrement semaphore value
4 Counting Semaphores • Safety • Liveness • Barging • Signaling • Exception propagation
4.1 First Attempt public class CountingSemaphore { private int value = 0; public CountingSemaphore(int initial) { if ( initial > 0 ) value = initial; }
4.1 First Attempt public synchronized void P() throws InterruptedException { if ( value = = 0 ) wait(); value--; }
4.1 First Attempt public synchronized void V() { if (value = = 0) notify(); value++; } } // End of class CountingSemaphore
4.2 Second Attempt public synchronized void P() throws InterruptedException { while ( value = = 0 ) wait(); value--; }
4.3 Third Attempt public synchronized void P() throws InterruptedException { value--; if ( value < 0 ) wait(); }
4.3 Third Attempt public synchronized void V() { value++; if ( value <= 0 ) notify(); }