View Javadoc

1   /***
2    *  Copyright 2003-2010 Terracotta, Inc.
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.concurrent;
18  
19  /***
20   * @version $Id: Sync.html 13146 2011-08-01 17:12:39Z oletizi $
21   * @author Doug Lea
22   * Main interface for locks, gates, and conditions.
23   * <p/>
24   * Sync objects isolate waiting and notification for particular
25   * logical states, resource availability, events, and the like that are
26   * shared across multiple threads. Use of Syncs sometimes
27   * (but by no means always) adds flexibility and efficiency
28   * compared to the use of plain java monitor methods
29   * and locking, and are sometimes (but by no means always)
30   * simpler to program with.
31   * <p/>
32   * <p/>
33   * Most Syncs are intended to be used primarily (although
34   * not exclusively) in  before/after constructions such as:
35   * <pre>
36   * class X {
37   *   Sync gate;
38   *   // ...
39   * <p/>
40   *   public void m() {
41   *     try {
42   *       gate.acquire();  // block until condition holds
43   *       try {
44   *         // ... method body
45   *       }
46   *       finally {
47   *         gate.release()
48   *       }
49   *     }
50   *     catch (InterruptedException ex) {
51   *       // ... evasive action
52   *     }
53   *   }
54   * <p/>
55   *   public void m2(Sync cond) { // use supplied condition
56   *     try {
57   *       if (cond.attempt(10)) {         // try the condition for 10 ms
58   *         try {
59   *           // ... method body
60   *         }
61   *         finally {
62   *           cond.release()
63   *         }
64   *       }
65   *     }
66   *     catch (InterruptedException ex) {
67   *       // ... evasive action
68   *     }
69   *   }
70   * }
71   * </pre>
72   * Syncs may be used in somewhat tedious but more flexible replacements
73   * for built-in Java synchronized blocks. For example:
74   * <pre>
75   * class HandSynched {
76   *   private double state_ = 0.0;
77   *   private final Sync lock;  // use lock type supplied in constructor
78   *   public HandSynched(Sync l) { lock = l; }
79   * <p/>
80   *   public void changeState(double d) {
81   *     try {
82   *       lock.acquire();
83   *       try     { state_ = updateFunction(d); }
84   *       finally { lock.release(); }
85   *     }
86   *     catch(InterruptedException ex) { }
87   *   }
88   * <p/>
89   *   public double getState() {
90   *     double d = 0.0;
91   *     try {
92   *       lock.acquire();
93   *       try     { d = accessFunction(state_); }
94   *       finally { lock.release(); }
95   *     }
96   *     catch(InterruptedException ex){}
97   *     return d;
98   *   }
99   *   private double updateFunction(double d) { ... }
100  *   private double accessFunction(double d) { ... }
101  * }
102  * </pre>
103  * If you have a lot of such methods, and they take a common
104  * form, you can standardize this using wrappers. Some of these
105  * wrappers are standardized in LockedExecutor, but you can make others.
106  * For example:
107  * <pre>
108  * class HandSynchedV2 {
109  *   private double state_ = 0.0;
110  *   private final Sync lock;  // use lock type supplied in constructor
111  *   public HandSynchedV2(Sync l) { lock = l; }
112  * <p/>
113  *   protected void runSafely(Runnable r) {
114  *     try {
115  *       lock.acquire();
116  *       try { r.run(); }
117  *       finally { lock.release(); }
118  *     }
119  *     catch (InterruptedException ex) { // propagate without throwing
120  *       Thread.currentThread().interrupt();
121  *     }
122  *   }
123  * <p/>
124  *   public void changeState(double d) {
125  *     runSafely(new Runnable() {
126  *       public void run() { state_ = updateFunction(d); }
127  *     });
128  *   }
129  *   // ...
130  * }
131  * </pre>
132  * <p/>
133  * One reason to bother with such constructions is to use deadlock-
134  * avoiding back-offs when dealing with locks involving multiple objects.
135  * For example, here is a Cell class that uses attempt to back-off
136  * and retry if two Cells are trying to swap values with each other
137  * at the same time.
138  * <pre>
139  * class Cell {
140  *   long value;
141  *   Sync lock = ... // some sync implementation class
142  *   void swapValue(Cell other) {
143  *     for (;;) {
144  *       try {
145  *         lock.acquire();
146  *         try {
147  *           if (other.lock.attempt(100)) {
148  *             try {
149  *               long t = value;
150  *               value = other.value;
151  *               other.value = t;
152  *               return;
153  *             }
154  *             finally { other.lock.release(); }
155  *           }
156  *         }
157  *         finally { lock.release(); }
158  *       }
159  *       catch (InterruptedException ex) { return; }
160  *     }
161  *   }
162  * }
163  * </pre>
164  * <p/>
165  * Here is an even fancier version, that uses lock re-ordering
166  * upon conflict:
167  * <pre>
168  * class Cell {
169  *   long value;
170  *   Sync lock = ...;
171  *   private static boolean trySwap(Cell a, Cell b) {
172  *     a.lock.acquire();
173  *     try {
174  *       if (!b.lock.attempt(0))
175  *         return false;
176  *       try {
177  *         long t = a.value;
178  *         a.value = b.value;
179  *         b.value = t;
180  *         return true;
181  *       }
182  *       finally { other.lock.release(); }
183  *     }
184  *     finally { lock.release(); }
185  *     return false;
186  *   }
187  * <p/>
188  *  void swapValue(Cell other) {
189  *    try {
190  *      while (!trySwap(this, other) &&
191  *            !tryswap(other, this))
192  *        Thread.sleep(1);
193  *    }
194  *    catch (InterruptedException ex) { return; }
195  *  }
196  * }
197  * </pre>
198  * <p/>
199  * Interruptions are in general handled as early as possible.
200  * Normally, InterruptionExceptions are thrown
201  * in acquire and attempt(msec) if interruption
202  * is detected upon entry to the method, as well as in any
203  * later context surrounding waits.
204  * However, interruption status is ignored in release();
205  * <p/>
206  * Timed versions of attempt report failure via return value.
207  * If so desired, you can transform such constructions to use exception
208  * throws via
209  * <pre>
210  *   if (!c.attempt(timeval)) throw new TimeoutException(timeval);
211  * </pre>
212  * <p/>
213  * The TimoutSync wrapper class can be used to automate such usages.
214  * <p/>
215  * All time values are expressed in milliseconds as longs, which have a maximum
216  * value of Long.MAX_VALUE, or almost 300,000 centuries. It is not
217  * known whether JVMs actually deal correctly with such extreme values.
218  * For convenience, some useful time values are defined as static constants.
219  * <p/>
220  * All implementations of the three Sync methods guarantee to
221  * somehow employ Java <code>synchronized</code> methods or blocks,
222  * and so entail the memory operations described in JLS
223  * chapter 17 which ensure that variables are loaded and flushed
224  * within before/after constructions.
225  * <p/>
226  * Syncs may also be used in spinlock constructions. Although
227  * it is normally best to just use acquire(), various forms
228  * of busy waits can be implemented. For a simple example
229  * (but one that would probably never be preferable to using acquire()):
230  * <pre>
231  * class X {
232  *   Sync lock = ...
233  *   void spinUntilAcquired() throws InterruptedException {
234  *     // Two phase.
235  *     // First spin without pausing.
236  *     int purespins = 10;
237  *     for (int i = 0; i < purespins; ++i) {
238  *       if (lock.attempt(0))
239  *         return true;
240  *     }
241  *     // Second phase - use timed waits
242  *     long waitTime = 1; // 1 millisecond
243  *     for (;;) {
244  *       if (lock.attempt(waitTime))
245  *         return true;
246  *       else
247  *         waitTime = waitTime * 3 / 2 + 1; // increase 50%
248  *     }
249  *   }
250  * }
251  * </pre>
252  * <p/>
253  * In addition pure synchronization control, Syncs
254  * may be useful in any context requiring before/after methods.
255  * For example, you can use an ObservableSync
256  * (perhaps as part of a LayeredSync) in order to obtain callbacks
257  * before and after each method invocation for a given class.
258  * <p/>
259  * <p/>
260  * <p>[<a href="http://gee.cs.oswego.edu/dl/classes/EDU/oswego/cs/dl/util/concurrent/intro.html"> Introduction to this package. </a>]
261  */
262 public interface Sync {
263     /***
264      * One second, in milliseconds; convenient as a time-out value *
265      */
266     long ONE_SECOND = 1000;
267 
268     /***
269      * One minute, in milliseconds; convenient as a time-out value *
270      */
271     long ONE_MINUTE = 60 * ONE_SECOND;
272 
273     /***
274      * One hour, in milliseconds; convenient as a time-out value *
275      */
276     long ONE_HOUR = 60 * ONE_MINUTE;
277 
278     /***
279      * One day, in milliseconds; convenient as a time-out value *
280      */
281     long ONE_DAY = 24 * ONE_HOUR;
282 
283     /***
284      * One week, in milliseconds; convenient as a time-out value *
285      */
286     long ONE_WEEK = 7 * ONE_DAY;
287 
288     /***
289      * One year in milliseconds; convenient as a time-out value
290      * Not that it matters, but there is some variation across
291      * standard sources about value at msec precision.
292      * The value used is the same as in java.util.GregorianCalendar
293      */
294     long ONE_YEAR = (long) (365.2425 * ONE_DAY);
295 
296     /***
297      * One century in milliseconds; convenient as a time-out value
298      */
299     long ONE_CENTURY = 100 * ONE_YEAR;
300 
301     /***
302      * Acquire lock of LockType.READ or WRITE
303      * @param type the lock type to acquire
304      */
305     void lock(LockType type);
306 
307     /***
308      * Tries to acquire a LockType.READ or WRITE for a certain period
309      * @param type the lock type to acquire
310      * @param msec timeout
311      * @return true if the lock got acquired, false otherwise
312      * @throws InterruptedException Should the thread be interrupted
313      */
314     boolean tryLock(LockType type, long msec) throws InterruptedException;
315 
316     /***
317      * Releases the lock held by the current Thread.
318      * In case of a LockType.WRITE, should the lock not be held by the current Thread, nothing happens 
319      * @param type the lock type to acquire
320      */
321     void unlock(LockType type);
322     
323     /***
324      * Returns true is this is lock is held at given level by the current thread.
325      * 
326      * @param type the lock type to test
327      * @return true if the lock is held
328      */
329     boolean isHeldByCurrentThread(LockType type);
330 }
331