Concurrency Patterns - Monitor Object

The pattern revolves around synchronization. In short, concurrent threads (clients) can only use the object via a set of synchronized methods. Only one method can run at a time. Typically a synchronized method watches for a certain condition. However, there is no polling involved. Instead, the methods are being notified. That's an important difference in comparison to the Active Object.

Monitor Object is similar to the Active Object in a sense that it exposes a defined interface via object's synchronized methods. On the other hand, the methods execute in the client's thread as there is no notion of a centralised thread control. There is no significant performance overhead either, Since inefficient busy-waiting loops (polling) are replaced with notifications.

Key Components




Advantages



Drawbacks



Example Implementation

Inspired by a blog post Java Monitor Pattern I came up with a hypothetical usage of a public toilet. Not only does it reminiscence of what makes us all equal, but it also comprises pattern's dominant attributes. A toilet is either occupied or vacant, hence the locked / unlocked parallel. It also should only be used by a single person at a time (race conditions).

Only a vacant toilet can be entered. Once in, the visitor is granted to leave:
 public interface Toilet {  
   boolean enter();  
   void quit();  
   boolean isOccupied();  
 }  
Now, the challenge is to ensure, under any circumstances, that the toilet only be used by a single person. Should that condition fail, the toilet becomes flooded:
public class ToiletFloodedException extends RuntimeException {
}  
An obviously ignorant implementation of the Toilet interface ..:
 public class FilthyToilet implements Toilet {  
   // a concurrent visitor counter.  
   private int counter = 0;  
   ..  
 }  
.. has unavoidable consequences: console output after having run the FilthyToiletMultiThreadedTest.java:
 The toilet was flooded 25 times under a moderate load.  
 The toilet was flooded 38 times under a heavy load.  
 The toilet was flooded 96 times under an extreme load.  
The correct implementation makes use of the Monitor Object pattern:
 public class CleanToilet implements Toilet {  
   // Monitor Lock used by the synchronized methods  
   private final ReentrantLock lock;  
   // Monitor Condition - the toilet can only   
   // be used by a single person at a time  
   private Condition oneAtATimeCondition;  
   // The guarded object's state - the 'volatile' flag   
   // is crucial for work signalling  
   private volatile int counter;  
   // all of the public methods are synchronized  
   ..  
 }  
The synchronization is ensured by using a lock along with a condition. The lock holds as long as the condition holds true:
 public boolean enter() {  
   lock.lock();  
   try {  
     while (counter > 0) {    
       // wait while the toilet is being used  
       oneAtATimeCondition.awaitUninterruptibly();  
     }  
     if (++counter == 1) {  
       // the toilet has been successfully acquired  
       oneAtATimeCondition.signal();    
     }  
     return isOccupied();  
   } finally {  
     lock.unlock();  
   }  
 }  

Source Code


Resources