001: /**
002: * Copyright 2003-2007 Luck Consulting Pty Ltd
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */package net.sf.ehcache.constructs.concurrent;
016:
017: /**
018: * @version $Id: Sync.java 519 2007-07-27 07:11:45Z gregluck $
019: * @author Doug Lea
020: * Main interface for locks, gates, and conditions.
021: * <p/>
022: * Sync objects isolate waiting and notification for particular
023: * logical states, resource availability, events, and the like that are
024: * shared across multiple threads. Use of Syncs sometimes
025: * (but by no means always) adds flexibility and efficiency
026: * compared to the use of plain java monitor methods
027: * and locking, and are sometimes (but by no means always)
028: * simpler to program with.
029: * <p/>
030: * <p/>
031: * Most Syncs are intended to be used primarily (although
032: * not exclusively) in before/after constructions such as:
033: * <pre>
034: * class X {
035: * Sync gate;
036: * // ...
037: * <p/>
038: * public void m() {
039: * try {
040: * gate.acquire(); // block until condition holds
041: * try {
042: * // ... method body
043: * }
044: * finally {
045: * gate.release()
046: * }
047: * }
048: * catch (InterruptedException ex) {
049: * // ... evasive action
050: * }
051: * }
052: * <p/>
053: * public void m2(Sync cond) { // use supplied condition
054: * try {
055: * if (cond.attempt(10)) { // try the condition for 10 ms
056: * try {
057: * // ... method body
058: * }
059: * finally {
060: * cond.release()
061: * }
062: * }
063: * }
064: * catch (InterruptedException ex) {
065: * // ... evasive action
066: * }
067: * }
068: * }
069: * </pre>
070: * Syncs may be used in somewhat tedious but more flexible replacements
071: * for built-in Java synchronized blocks. For example:
072: * <pre>
073: * class HandSynched {
074: * private double state_ = 0.0;
075: * private final Sync lock; // use lock type supplied in constructor
076: * public HandSynched(Sync l) { lock = l; }
077: * <p/>
078: * public void changeState(double d) {
079: * try {
080: * lock.acquire();
081: * try { state_ = updateFunction(d); }
082: * finally { lock.release(); }
083: * }
084: * catch(InterruptedException ex) { }
085: * }
086: * <p/>
087: * public double getState() {
088: * double d = 0.0;
089: * try {
090: * lock.acquire();
091: * try { d = accessFunction(state_); }
092: * finally { lock.release(); }
093: * }
094: * catch(InterruptedException ex){}
095: * return d;
096: * }
097: * private double updateFunction(double d) { ... }
098: * private double accessFunction(double d) { ... }
099: * }
100: * </pre>
101: * If you have a lot of such methods, and they take a common
102: * form, you can standardize this using wrappers. Some of these
103: * wrappers are standardized in LockedExecutor, but you can make others.
104: * For example:
105: * <pre>
106: * class HandSynchedV2 {
107: * private double state_ = 0.0;
108: * private final Sync lock; // use lock type supplied in constructor
109: * public HandSynchedV2(Sync l) { lock = l; }
110: * <p/>
111: * protected void runSafely(Runnable r) {
112: * try {
113: * lock.acquire();
114: * try { r.run(); }
115: * finally { lock.release(); }
116: * }
117: * catch (InterruptedException ex) { // propagate without throwing
118: * Thread.currentThread().interrupt();
119: * }
120: * }
121: * <p/>
122: * public void changeState(double d) {
123: * runSafely(new Runnable() {
124: * public void run() { state_ = updateFunction(d); }
125: * });
126: * }
127: * // ...
128: * }
129: * </pre>
130: * <p/>
131: * One reason to bother with such constructions is to use deadlock-
132: * avoiding back-offs when dealing with locks involving multiple objects.
133: * For example, here is a Cell class that uses attempt to back-off
134: * and retry if two Cells are trying to swap values with each other
135: * at the same time.
136: * <pre>
137: * class Cell {
138: * long value;
139: * Sync lock = ... // some sync implementation class
140: * void swapValue(Cell other) {
141: * for (;;) {
142: * try {
143: * lock.acquire();
144: * try {
145: * if (other.lock.attempt(100)) {
146: * try {
147: * long t = value;
148: * value = other.value;
149: * other.value = t;
150: * return;
151: * }
152: * finally { other.lock.release(); }
153: * }
154: * }
155: * finally { lock.release(); }
156: * }
157: * catch (InterruptedException ex) { return; }
158: * }
159: * }
160: * }
161: * </pre>
162: * <p/>
163: * Here is an even fancier version, that uses lock re-ordering
164: * upon conflict:
165: * <pre>
166: * class Cell {
167: * long value;
168: * Sync lock = ...;
169: * private static boolean trySwap(Cell a, Cell b) {
170: * a.lock.acquire();
171: * try {
172: * if (!b.lock.attempt(0))
173: * return false;
174: * try {
175: * long t = a.value;
176: * a.value = b.value;
177: * b.value = t;
178: * return true;
179: * }
180: * finally { other.lock.release(); }
181: * }
182: * finally { lock.release(); }
183: * return false;
184: * }
185: * <p/>
186: * void swapValue(Cell other) {
187: * try {
188: * while (!trySwap(this, other) &&
189: * !tryswap(other, this))
190: * Thread.sleep(1);
191: * }
192: * catch (InterruptedException ex) { return; }
193: * }
194: * }
195: * </pre>
196: * <p/>
197: * Interruptions are in general handled as early as possible.
198: * Normally, InterruptionExceptions are thrown
199: * in acquire and attempt(msec) if interruption
200: * is detected upon entry to the method, as well as in any
201: * later context surrounding waits.
202: * However, interruption status is ignored in release();
203: * <p/>
204: * Timed versions of attempt report failure via return value.
205: * If so desired, you can transform such constructions to use exception
206: * throws via
207: * <pre>
208: * if (!c.attempt(timeval)) throw new TimeoutException(timeval);
209: * </pre>
210: * <p/>
211: * The TimoutSync wrapper class can be used to automate such usages.
212: * <p/>
213: * All time values are expressed in milliseconds as longs, which have a maximum
214: * value of Long.MAX_VALUE, or almost 300,000 centuries. It is not
215: * known whether JVMs actually deal correctly with such extreme values.
216: * For convenience, some useful time values are defined as static constants.
217: * <p/>
218: * All implementations of the three Sync methods guarantee to
219: * somehow employ Java <code>synchronized</code> methods or blocks,
220: * and so entail the memory operations described in JLS
221: * chapter 17 which ensure that variables are loaded and flushed
222: * within before/after constructions.
223: * <p/>
224: * Syncs may also be used in spinlock constructions. Although
225: * it is normally best to just use acquire(), various forms
226: * of busy waits can be implemented. For a simple example
227: * (but one that would probably never be preferable to using acquire()):
228: * <pre>
229: * class X {
230: * Sync lock = ...
231: * void spinUntilAcquired() throws InterruptedException {
232: * // Two phase.
233: * // First spin without pausing.
234: * int purespins = 10;
235: * for (int i = 0; i < purespins; ++i) {
236: * if (lock.attempt(0))
237: * return true;
238: * }
239: * // Second phase - use timed waits
240: * long waitTime = 1; // 1 millisecond
241: * for (;;) {
242: * if (lock.attempt(waitTime))
243: * return true;
244: * else
245: * waitTime = waitTime * 3 / 2 + 1; // increase 50%
246: * }
247: * }
248: * }
249: * </pre>
250: * <p/>
251: * In addition pure synchronization control, Syncs
252: * may be useful in any context requiring before/after methods.
253: * For example, you can use an ObservableSync
254: * (perhaps as part of a LayeredSync) in order to obtain callbacks
255: * before and after each method invocation for a given class.
256: * <p/>
257: * <p/>
258: * <p>[<a href="http://gee.cs.oswego.edu/dl/classes/EDU/oswego/cs/dl/util/concurrent/intro.html"> Introduction to this package. </a>]
259: */
260: public interface Sync {
261: /**
262: * One second, in milliseconds; convenient as a time-out value *
263: */
264: long ONE_SECOND = 1000;
265:
266: /**
267: * One minute, in milliseconds; convenient as a time-out value *
268: */
269: long ONE_MINUTE = 60 * ONE_SECOND;
270:
271: /**
272: * One hour, in milliseconds; convenient as a time-out value *
273: */
274: long ONE_HOUR = 60 * ONE_MINUTE;
275:
276: /**
277: * One day, in milliseconds; convenient as a time-out value *
278: */
279: long ONE_DAY = 24 * ONE_HOUR;
280:
281: /**
282: * One week, in milliseconds; convenient as a time-out value *
283: */
284: long ONE_WEEK = 7 * ONE_DAY;
285:
286: /**
287: * One year in milliseconds; convenient as a time-out value
288: * Not that it matters, but there is some variation across
289: * standard sources about value at msec precision.
290: * The value used is the same as in java.util.GregorianCalendar
291: */
292: long ONE_YEAR = (long) (365.2425 * ONE_DAY);
293:
294: /**
295: * One century in milliseconds; convenient as a time-out value
296: */
297: long ONE_CENTURY = 100 * ONE_YEAR;
298:
299: /**
300: * Wait (possibly forever) until successful passage.
301: * Fail only upon interuption. Interruptions always result in
302: * `clean' failures. On failure, you can be sure that it has not
303: * been acquired, and that no
304: * corresponding release should be performed. Conversely,
305: * a normal return guarantees that the acquire was successful.
306: */
307: void acquire() throws InterruptedException;
308:
309: /**
310: * Wait at most msecs to pass; report whether passed.
311: * <p/>
312: * The method has best-effort semantics:
313: * The msecs bound cannot
314: * be guaranteed to be a precise upper bound on wait time in Java.
315: * Implementations generally can only attempt to return as soon as possible
316: * after the specified bound. Also, timers in Java do not stop during garbage
317: * collection, so timeouts can occur just because a GC intervened.
318: * So, msecs arguments should be used in
319: * a coarse-grained manner. Further,
320: * implementations cannot always guarantee that this method
321: * will return at all without blocking indefinitely when used in
322: * unintended ways. For example, deadlocks may be encountered
323: * when called in an unintended context.
324: * <p/>
325: *
326: * @param msecs the number of milleseconds to wait.
327: * An argument less than or equal to zero means not to wait at all.
328: * However, this may still require
329: * access to a synchronization lock, which can impose unbounded
330: * delay if there is a lot of contention among threads.
331: * @return true if acquired
332: */
333: boolean attempt(long msecs) throws InterruptedException;
334:
335: /**
336: * Potentially enable others to pass.
337: * <p/>
338: * Because release does not raise exceptions,
339: * it can be used in `finally' clauses without requiring extra
340: * embedded try/catch blocks. But keep in mind that
341: * as with any java method, implementations may
342: * still throw unchecked exceptions such as Error or NullPointerException
343: * when faced with uncontinuable errors. However, these should normally
344: * only be caught by higher-level error handlers.
345: */
346: void release();
347: }
|