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