[]
[]
accessalgorithms[See also interfaces][See APIs]arrays
[]
blocks
[]
classes[See collection classes]clientscompiling[See also race condition]
[]
[]
errorsexecution
[]
flags
[]
[]
[]
I/Oimplementationsinterfaces
[]
[]
keywords
[]
loops
[]
main memorymanagementmemorymethodsmodificationmultiple threads
[]
native threads[See also wait-and-notify mechanism]
[]
Swingoperating system (OS)[See operating system]
[]
patternsprinting
[]
queues
[]
[See also synchronization]running
[]
scalingserverssettingsharingsizesstacksSwing
[]
terminationtestingthreadsthreadsafetimetimeoutsTimer class
[]
[]
valuesvariables
[]
A.1 The BusyFlag Class
We'll start witha BusyFlag class:
package javathreads.examples.appa;public class BusyFlag { protected Thread busyflag = null; protected int busycount = 0; public synchronized void getBusyFlag( ) { while (tryGetBusyFlag( ) == false) { try { wait( ); } catch (Exception e) {} } } public synchronized boolean tryGetBusyFlag( ) { if (busyflag == null) { busyflag = Thread.currentThread( ); busycount = 1; return true; } if (busyflag == Thread.currentThread( )) { busycount++; return true; } return false; } public synchronized void freeBusyFlag( ) { if (getBusyFlagOwner( ) == Thread.currentThread( )) { busycount--; if (busycount == 0) { busyflag = null; notify( ); } } } public synchronized Thread getBusyFlagOwner( ) { return busyflag; }}
The BusyFlag class implements a basic, no-frills,mutually exclusive lock. It also allows the locks to benestedthe owner thread can lock the busy flag multiple times.It is much simpler than the ReentrantLock class. There is no internal support forcondition variables. There is no support for timeouts. There is noconcept of fairness in granting the busy flag. And our implementationdoes not attempt to minimize synchronization.
Simplistically, the purpose of this class is to useJava's basic synchronization mechanism to achieve,well, synchronization. This allows the program to lock at any scopeor for any purpose.
The BusyFlag class contains four methods. The tryGetBusyFlag() class is used to obtain a lock(a.k.a. the busyflag ). It grabs the busy flag ifit is available while returning false if the flagis already owned by another thread. It also allows nested locks byincrementing a counter if the current thread already owns the flag.The synchronized keyword is used to protectagainst race conditions while grabbing this flag.
The getBusyFlag() method uses the tryGetBusyFlag() method to repeatedly trygrabbing the flag until it is successful. If the flag is notavailable, it uses the wait-and-notify mechanism to wait for the flagto be returned. The freeBusyFlag() methoddecrements the counter. And if the counter is zero, this methoddeclares that the flag has no owner and notifies any threads that arewaiting to grab the flag.
The getBusyFlagOwner() method is merely anadministration method that allows a thread to determine who is theowner of the busy flag. Also note that due to a race condition, theresult that is returned is only guaranteed not to change if thecurrent thread is returned as the owner of the busy flag.
A.2 The CondVar Class
Here is an implementation ofthe CondVar class:
package javathreads.examples.appa;public class CondVar { private BusyFlag SyncVar; public CondVar( ) { this(new BusyFlag( )); } public CondVar(BusyFlag sv) { SyncVar = sv; } public void cvWait( ) throws InterruptedException { cvTimedWait(SyncVar, 0); } public void cvWait(BusyFlag sv) throws InterruptedException { cvTimedWait(sv, 0); } public void cvTimedWait(int millis) throws InterruptedException { cvTimedWait(SyncVar, millis); } public void cvTimedWait(BusyFlag sv, int millis) throws InterruptedException { int i = 0; InterruptedException errex = null; synchronized (this) { // You must own the lock in order to use this method if (sv.getBusyFlagOwner( ) != Thread.currentThread( )) { throw new IllegalMonitorStateException( "current thread not owner"); } // Release the lock (Completely) while (sv.getBusyFlagOwner( ) == Thread.currentThread( )) { i++; sv.freeBusyFlag( ); } // Use wait( ) method try { if (millis == 0) { wait( ); } else { wait(millis); } } catch (InterruptedException iex) { errex = iex; } } // Obtain the lock (Return to original state) for (; i>0; i--) { sv.getBusyFlag( ); } if (errex != null) throw errex; return; } public void cvSignal( ) { cvSignal(SyncVar); } public synchronized void cvSignal(BusyFlag sv) { // You must own the lock in order to use this method if (sv.getBusyFlagOwner( ) != Thread.currentThread( )) { throw new IllegalMonitorStateException( "current thread not owner"); } notify( ); } public void cvBroadcast( ) { cvBroadcast(SyncVar); } public synchronized void cvBroadcast(BusyFlag sv) { // You must own the lock in order to use this method if (sv.getBusyFlagOwner( ) != Thread.currentThread( )) { throw new IllegalMonitorStateException( "current thread not owner"); } notifyAll( ); }}
The CondVar class implements a basic conditionvariable for use with the BusyFlag class. There isno concept of fairness in notification. It is constructed separatelyfrom the BusyFlag classas compared to Condition objects, which are generated from the Lock class via the newCondition() method. And like the BusyFlag class,the implementation doesn't attempt to minimizesynchronization.
The purpose of this class is to allow Java'swait-and-notify mechanism to work with explicit locking (locks at anyscope). This allows the program to have condition variable supportfor the BusyFlag class. It also allows a singlelock to have more than one condition variable, where thewait-and-notify mechanism needs a separate object for every type ofnotification.
The CondVar class provides four methods forwaiting for notification; three of these methods can be consideredconvenience methods. The primary method is the cvTimedWait() method. This method frees the ownership of the busy flagcompletely and then uses the standard wait() method to perform the wait. If the time to wait is zero, this methodwaits indefinitely for the notification. Otherwise, it uses thetimeout specified. Upon returning, it grabs the lock (note that itmust do that as many times as the lock was released to support thenesting semantics of our BusyFlag class). Alsonote that it may still wait upon receiving notification as it canstill block while reacquiring the flag. In fact,that's the case with all notification-basedtechniques (the Condition class, thewait-and-notify mechanism); it's just in this codethat you see the effect explicitly.
Two of the convenience methods allow the program to specify a timeoutor wait indefinitely. The last one allows you to specify an alternatebusy flag classa flag that is different from the one specifiedduring construction. Specifying an alternate busy flag is not afeature supported by the Condition classa Condition instance is tightly bound to the Lock instance from which it was obtained. Thisfeature allows notification between two groups of threads that areoperating on different locks. In terms of functionality, this is aminor enhancement for a very rare need. Using the Condition class, a common Lock object could be created just for notification between the two groupsof threads to achieve the same thing.
The cvSignal() method is used to send a singlenotificationusing the notify() method. Aswith the wait methods, it is overloaded to allow the program tospecify an alternate busy flag. The cvBroadcast() method is used to send notifications to all the waitingthreadsusing the notifyAll() method. It,too, is overloaded to allow the program to specify an alternate busyflag.
A.3 The Barrier Class
Here is an implementation ofthe Barrier class:
package javathreads.examples.appa;public class Barrier { private int threads2Wait4; private InterruptedException iex; public Barrier (int nThreads) { threads2Wait4 = nThreads; } public synchronized int waitForRest( ) throws InterruptedException { int threadNum = --threads2Wait4; if (iex != null) throw iex; if (threads2Wait4 <= 0) { notifyAll( ); return threadNum; } while (threads2Wait4 > 0) { if (iex != null) throw iex; try { wait( ); } catch (InterruptedException ex) { iex = ex; notifyAll( ); } } return threadNum; } public synchronized void freeAll( ) { iex = new InterruptedException("Barrier Released by freeAll"); notifyAll( ); }}
Next page