View Javadoc

1   /**
2    *  Copyright 2003-2007 Greg Luck
3    *
4    *  Licensed under the Apache License, Version 2.0 (the "License");
5    *  you may not use this file except in compliance with the License.
6    *  You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   *  Unless required by applicable law or agreed to in writing, software
11   *  distributed under the License is distributed on an "AS IS" BASIS,
12   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   *  See the License for the specific language governing permissions and
14   *  limitations under the License.
15   */
16  
17  package net.sf.ehcache.constructs.concurrent;
18  
19  /**
20   * @version $Id: Mutex.java 512 2007-07-10 09:18:45Z gregluck $
21   * @author Doug Lea
22   * A simple non-reentrant mutual exclusion lock.
23   * The lock is free upon construction. Each acquire gets the
24   * lock, and each release frees it. Releasing a lock that
25   * is already free has no effect.
26   * <p/>
27   * This implementation makes no attempt to provide any fairness
28   * or ordering guarantees. If you need them, consider using one of
29   * the Semaphore implementations as a locking mechanism.
30   * <p/>
31   * <b>Sample usage</b><br>
32   * <p/>
33   * Mutex can be useful in constructions that cannot be
34   * expressed using java synchronized blocks because the
35   * acquire/release pairs do not occur in the same method or
36   * code block. For example, you can use them for hand-over-hand
37   * locking across the nodes of a linked list. This allows
38   * extremely fine-grained locking,  and so increases
39   * potential concurrency, at the cost of additional complexity and
40   * overhead that would normally make this worthwhile only in cases of
41   * extreme contention.
42   * <pre>
43   * class Node {
44   *   Object item;
45   *   Node next;
46   *   Mutex lock = new Mutex(); // each node keeps its own lock
47   * <p/>
48   *   Node(Object x, Node n) { item = x; next = n; }
49   * }
50   * <p/>
51   * class List {
52   *    protected Node head; // pointer to first node of list
53   * <p/>
54   *    // Use plain java synchronization to protect head field.
55   *    //  (We could instead use a Mutex here too but there is no
56   *    //  reason to do so.)
57   *    protected synchronized Node getHead() { return head; }
58   * <p/>
59   *    boolean search(Object x) throws InterruptedException {
60   *      Node p = getHead();
61   *      if (p == null) return false;
62   * <p/>
63   *      //  (This could be made more compact, but for clarity of illustration,
64   *      //  all of the cases that can arise are handled separately.)
65   * <p/>
66   *      p.lock.acquire();              // Prime loop by acquiring first lock.
67   *                                     //    (If the acquire fails due to
68   *                                     //    interrupt, the method will throw
69   *                                     //    InterruptedException now,
70   *                                     //    so there is no need for any
71   *                                     //    further cleanup.)
72   *      for (;;) {
73   *        if (x.equals(p.item)) {
74   *          p.lock.release();          // release current before return
75   *          return true;
76   *        }
77   *        else {
78   *          Node nextp = p.next;
79   *          if (nextp == null) {
80   *            p.lock.release();       // release final lock that was held
81   *            return false;
82   *          }
83   *          else {
84   *            try {
85   *              nextp.lock.acquire(); // get next lock before releasing current
86   *            }
87   *            catch (InterruptedException ex) {
88   *              p.lock.release();    // also release current if acquire fails
89   *              throw ex;
90   *            }
91   *            p.lock.release();      // release old lock now that new one held
92   *            p = nextp;
93   *          }
94   *        }
95   *      }
96   *    }
97   * <p/>
98   *    synchronized void add(Object x) { // simple prepend
99   *      // The use of `synchronized'  here protects only head field.
100  *      // The method does not need to wait out other traversers
101  *      // who have already made it past head.
102  * <p/>
103  *      head = new Node(x, head);
104  *    }
105  * <p/>
106  *    // ...  other similar traversal and update methods ...
107  * }
108  * </pre>
109  * <p/>
110  * <p>[<a href="http://gee.cs.oswego.edu/dl/classes/EDU/oswego/cs/dl/util/concurrent/intro.html"> Introduction to this package. </a>]
111  */
112 public class Mutex implements Sync {
113     /**
114      * The lock status *
115      */
116     protected boolean inUse;
117 
118     /**
119      * Wait (possibly forever) until successful passage.
120      * Fail only upon interuption. Interruptions always result in
121      * `clean' failures. On failure,  you can be sure that it has not
122      * been acquired, and that no
123      * corresponding release should be performed. Conversely,
124      * a normal return guarantees that the acquire was successful.
125      * @see Sync#acquire() 
126      */
127     public void acquire() throws InterruptedException {
128         if (Thread.interrupted()) {
129             throw new InterruptedException();
130         }
131         synchronized (this) {
132             try {
133                 while (inUse) {
134                     wait();
135                 }
136                 inUse = true;
137             } catch (InterruptedException ex) {
138                 notify();
139                 throw ex;
140             }
141         }
142     }
143 
144     /**
145      * @param msecs the number of milleseconds to wait.
146      *              An argument less than or equal to zero means not to wait at all.
147      *              However, this may still require
148      *              access to a synchronization lock, which can impose unbounded
149      *              delay if there is a lot of contention among threads.
150      * @return true if acquired
151      * @see Sync#attempt(long)
152      */
153     public boolean attempt(long msecs) throws InterruptedException {
154         if (Thread.interrupted()) {
155             throw new InterruptedException();
156         }
157         synchronized (this) {
158             if (!inUse) {
159                 inUse = true;
160                 return true;
161             } else if (msecs <= 0) {
162                 return false;
163             } else {
164                 long waitTime = msecs;
165                 long start = System.currentTimeMillis();
166                 try {
167                     for (;;) {
168                         wait(waitTime);
169                         if (!inUse) {
170                             inUse = true;
171                             return true;
172                         } else {
173                             waitTime = msecs - (System.currentTimeMillis() - start);
174                             if (waitTime <= 0) {
175                                 return false;
176                             }
177                         }
178                     }
179                 } catch (InterruptedException ex) {
180                     notify();
181                     throw ex;
182                 }
183             }
184         }
185     }
186 
187     /**
188      * Potentially enable others to pass.
189      * <p/>
190      * Because release does not raise exceptions,
191      * it can be used in `finally' clauses without requiring extra
192      * embedded try/catch blocks. But keep in mind that
193      * as with any java method, implementations may
194      * still throw unchecked exceptions such as Error or NullPointerException
195      * when faced with uncontinuable errors. However, these should normally
196      * only be caught by higher-level error handlers.
197      * @see Sync#release()
198      */
199     public synchronized void release() {
200         inUse = false;
201         notify();
202     }
203 }
204