Save This Page
Home » concurrent-sources » EDU.oswego.cs.dl.util.concurrent » [javadoc | source]
    1   /*
    2     File: Mutex.java
    3   
    4     Originally written by Doug Lea and released into the public domain.
    5     This may be used for any purposes whatsoever without acknowledgment.
    6     Thanks for the assistance and support of Sun Microsystems Labs,
    7     and everyone contributing, testing, and using this code.
    8   
    9     History:
   10     Date       Who                What
   11     11Jun1998  dl               Create public version
   12   */
   13   
   14   package EDU.oswego.cs.dl.util.concurrent;
   15   
   16   /**
   17    * A simple non-reentrant mutual exclusion lock.
   18    * The lock is free upon construction. Each acquire gets the
   19    * lock, and each release frees it. Releasing a lock that
   20    * is already free has no effect. 
   21    * <p>
   22    * This implementation makes no attempt to provide any fairness
   23    * or ordering guarantees. If you need them, consider using one of
   24    * the Semaphore implementations as a locking mechanism.
   25    * <p>
   26    * <b>Sample usage</b><br>
   27    * <p>
   28    * Mutex can be useful in constructions that cannot be
   29    * expressed using java synchronized blocks because the
   30    * acquire/release pairs do not occur in the same method or
   31    * code block. For example, you can use them for hand-over-hand
   32    * locking across the nodes of a linked list. This allows
   33    * extremely fine-grained locking,  and so increases 
   34    * potential concurrency, at the cost of additional complexity and
   35    * overhead that would normally make this worthwhile only in cases of
   36    * extreme contention.
   37    * <pre>
   38    * class Node { 
   39    *   Object item; 
   40    *   Node next; 
   41    *   Mutex lock = new Mutex(); // each node keeps its own lock
   42    *
   43    *   Node(Object x, Node n) { item = x; next = n; }
   44    * }
   45    *
   46    * class List {
   47    *    protected Node head; // pointer to first node of list
   48    *
   49    *    // Use plain java synchronization to protect head field.
   50    *    //  (We could instead use a Mutex here too but there is no
   51    *    //  reason to do so.)
   52    *    protected synchronized Node getHead() { return head; }
   53    *
   54    *    boolean search(Object x) throws InterruptedException {
   55    *      Node p = getHead();
   56    *      if (p == null) return false;
   57    *
   58    *      //  (This could be made more compact, but for clarity of illustration,
   59    *      //  all of the cases that can arise are handled separately.)
   60    *
   61    *      p.lock.acquire();              // Prime loop by acquiring first lock.
   62    *                                     //    (If the acquire fails due to
   63    *                                     //    interrupt, the method will throw
   64    *                                     //    InterruptedException now,
   65    *                                     //    so there is no need for any
   66    *                                     //    further cleanup.)
   67    *      for (;;) {
   68    *        if (x.equals(p.item)) {
   69    *          p.lock.release();          // release current before return
   70    *          return true;
   71    *        }
   72    *        else {
   73    *          Node nextp = p.next;
   74    *          if (nextp == null) {
   75    *            p.lock.release();       // release final lock that was held
   76    *            return false;
   77    *          }
   78    *          else {
   79    *            try {
   80    *              nextp.lock.acquire(); // get next lock before releasing current
   81    *            }
   82    *            catch (InterruptedException ex) {
   83    *              p.lock.release();    // also release current if acquire fails
   84    *              throw ex;
   85    *            }
   86    *            p.lock.release();      // release old lock now that new one held
   87    *            p = nextp;
   88    *          }
   89    *        }
   90    *      }
   91    *    }
   92    *
   93    *    synchronized void add(Object x) { // simple prepend
   94    *      // The use of `synchronized'  here protects only head field.
   95    *      // The method does not need to wait out other traversers 
   96    *      // who have already made it past head.
   97    *
   98    *      head = new Node(x, head);
   99    *    }
  100    *
  101    *    // ...  other similar traversal and update methods ...
  102    * }
  103    * </pre>
  104    * <p>
  105    * @see Semaphore
  106    * <p>[<a href="http://gee.cs.oswego.edu/dl/classes/EDU/oswego/cs/dl/util/concurrent/intro.html"> Introduction to this package. </a>]
  107   **/
  108   
  109   public class Mutex implements Sync  {
  110   
  111     /** The lock status **/
  112     protected boolean inuse_ = false;
  113   
  114     public void acquire() throws InterruptedException {
  115       if (Thread.interrupted()) throw new InterruptedException();
  116       synchronized(this) {
  117         try {
  118           while (inuse_) wait();
  119           inuse_ = true;
  120         }
  121         catch (InterruptedException ex) {
  122           notify();
  123           throw ex;
  124         }
  125       }
  126     }
  127   
  128     public synchronized void release()  {
  129       inuse_ = false;
  130       notify(); 
  131     }
  132   
  133   
  134     public boolean attempt(long msecs) throws InterruptedException {
  135       if (Thread.interrupted()) throw new InterruptedException();
  136       synchronized(this) {
  137         if (!inuse_) {
  138           inuse_ = true;
  139           return true;
  140         }
  141         else if (msecs <= 0)
  142           return false;
  143         else {
  144           long waitTime = msecs;
  145           long start = System.currentTimeMillis();
  146           try {
  147             for (;;) {
  148               wait(waitTime);
  149               if (!inuse_) {
  150                 inuse_ = true;
  151                 return true;
  152               }
  153               else {
  154                 waitTime = msecs - (System.currentTimeMillis() - start);
  155                 if (waitTime <= 0) 
  156                   return false;
  157               }
  158             }
  159           }
  160           catch (InterruptedException ex) {
  161             notify();
  162             throw ex;
  163           }
  164         }
  165       }  
  166     }
  167   
  168   }
  169   

Save This Page
Home » concurrent-sources » EDU.oswego.cs.dl.util.concurrent » [javadoc | source]