- /*
- File: Sync.java
-
- Originally written by Doug Lea and released into the public domain.
- This may be used for any purposes whatsoever without acknowledgment.
- Thanks for the assistance and support of Sun Microsystems Labs,
- and everyone contributing, testing, and using this code.
-
- History:
- Date Who What
- 11Jun1998 dl Create public version
- 5Aug1998 dl Added some convenient time constants
- */
-
- package com.sun.corba.se.impl.orbutil.concurrent;
-
- /**
- * Main interface for locks, gates, and conditions.
- * <p>
- * Sync objects isolate waiting and notification for particular
- * logical states, resource availability, events, and the like that are
- * shared across multiple threads. Use of Syncs sometimes
- * (but by no means always) adds flexibility and efficiency
- * compared to the use of plain java monitor methods
- * and locking, and are sometimes (but by no means always)
- * simpler to program with.
- * <p>
- *
- * Most Syncs are intended to be used primarily (although
- * not exclusively) in before/after constructions such as:
- * <pre>
- * class X {
- * Sync gate;
- * // ...
- *
- * public void m() {
- * try {
- * gate.acquire(); // block until condition holds
- * try {
- * // ... method body
- * }
- * finally {
- * gate.release()
- * }
- * }
- * catch (InterruptedException ex) {
- * // ... evasive action
- * }
- * }
- *
- * public void m2(Sync cond) { // use supplied condition
- * try {
- * if (cond.attempt(10)) { // try the condition for 10 ms
- * try {
- * // ... method body
- * }
- * finally {
- * cond.release()
- * }
- * }
- * }
- * catch (InterruptedException ex) {
- * // ... evasive action
- * }
- * }
- * }
- * </pre>
- * Syncs may be used in somewhat tedious but more flexible replacements
- * for built-in Java synchronized blocks. For example:
- * <pre>
- * class HandSynched {
- * private double state_ = 0.0;
- * private final Sync lock; // use lock type supplied in constructor
- * public HandSynched(Sync l) { lock = l; }
- *
- * public void changeState(double d) {
- * try {
- * lock.acquire();
- * try { state_ = updateFunction(d); }
- * finally { lock.release(); }
- * }
- * catch(InterruptedException ex) { }
- * }
- *
- * public double getState() {
- * double d = 0.0;
- * try {
- * lock.acquire();
- * try { d = accessFunction(state_); }
- * finally { lock.release(); }
- * }
- * catch(InterruptedException ex){}
- * return d;
- * }
- * private double updateFunction(double d) { ... }
- * private double accessFunction(double d) { ... }
- * }
- * </pre>
- * If you have a lot of such methods, and they take a common
- * form, you can standardize this using wrappers. Some of these
- * wrappers are standardized in LockedExecutor, but you can make others.
- * For example:
- * <pre>
- * class HandSynchedV2 {
- * private double state_ = 0.0;
- * private final Sync lock; // use lock type supplied in constructor
- * public HandSynchedV2(Sync l) { lock = l; }
- *
- * protected void runSafely(Runnable r) {
- * try {
- * lock.acquire();
- * try { r.run(); }
- * finally { lock.release(); }
- * }
- * catch (InterruptedException ex) { // propagate without throwing
- * Thread.currentThread().interrupt();
- * }
- * }
- *
- * public void changeState(double d) {
- * runSafely(new Runnable() {
- * public void run() { state_ = updateFunction(d); }
- * });
- * }
- * // ...
- * }
- * </pre>
- * <p>
- * One reason to bother with such constructions is to use deadlock-
- * avoiding back-offs when dealing with locks involving multiple objects.
- * For example, here is a Cell class that uses attempt to back-off
- * and retry if two Cells are trying to swap values with each other
- * at the same time.
- * <pre>
- * class Cell {
- * long value;
- * Sync lock = ... // some sync implementation class
- * void swapValue(Cell other) {
- * for (;;) {
- * try {
- * lock.acquire();
- * try {
- * if (other.lock.attempt(100)) {
- * try {
- * long t = value;
- * value = other.value;
- * other.value = t;
- * return;
- * }
- * finally { other.lock.release(); }
- * }
- * }
- * finally { lock.release(); }
- * }
- * catch (InterruptedException ex) { return; }
- * }
- * }
- * }
- *</pre>
- * <p>
- * Here is an even fancier version, that uses lock re-ordering
- * upon conflict:
- * <pre>
- * class Cell {
- * long value;
- * Sync lock = ...;
- * private static boolean trySwap(Cell a, Cell b) {
- * a.lock.acquire();
- * try {
- * if (!b.lock.attempt(0))
- * return false;
- * try {
- * long t = a.value;
- * a.value = b.value;
- * b.value = t;
- * return true;
- * }
- * finally { other.lock.release(); }
- * }
- * finally { lock.release(); }
- * return false;
- * }
- *
- * void swapValue(Cell other) {
- * try {
- * while (!trySwap(this, other) &&
- * !tryswap(other, this))
- * Thread.sleep(1);
- * }
- * catch (InterruptedException ex) { return; }
- * }
- *}
- *</pre>
- * <p>
- * Interruptions are in general handled as early as possible.
- * Normally, InterruptionExceptions are thrown
- * in acquire and attempt(msec) if interruption
- * is detected upon entry to the method, as well as in any
- * later context surrounding waits.
- * However, interruption status is ignored in release();
- * <p>
- * Timed versions of attempt report failure via return value.
- * If so desired, you can transform such constructions to use exception
- * throws via
- * <pre>
- * if (!c.attempt(timeval)) throw new TimeoutException(timeval);
- * </pre>
- * <p>
- * The TimoutSync wrapper class can be used to automate such usages.
- * <p>
- * All time values are expressed in milliseconds as longs, which have a maximum
- * value of Long.MAX_VALUE, or almost 300,000 centuries. It is not
- * known whether JVMs actually deal correctly with such extreme values.
- * For convenience, some useful time values are defined as static constants.
- * <p>
- * All implementations of the three Sync methods guarantee to
- * somehow employ Java <code>synchronized</code> methods or blocks,
- * and so entail the memory operations described in JLS
- * chapter 17 which ensure that variables are loaded and flushed
- * within before/after constructions.
- * <p>
- * Syncs may also be used in spinlock constructions. Although
- * it is normally best to just use acquire(), various forms
- * of busy waits can be implemented. For a simple example
- * (but one that would probably never be preferable to using acquire()):
- * <pre>
- * class X {
- * Sync lock = ...
- * void spinUntilAcquired() throws InterruptedException {
- * // Two phase.
- * // First spin without pausing.
- * int purespins = 10;
- * for (int i = 0; i < purespins; ++i) {
- * if (lock.attempt(0))
- * return true;
- * }
- * // Second phase - use timed waits
- * long waitTime = 1; // 1 millisecond
- * for (;;) {
- * if (lock.attempt(waitTime))
- * return true;
- * else
- * waitTime = waitTime * 3 / 2 + 1; // increase 50%
- * }
- * }
- * }
- * </pre>
- * <p>
- * In addition pure synchronization control, Syncs
- * may be useful in any context requiring before/after methods.
- * For example, you can use an ObservableSync
- * (perhaps as part of a LayeredSync) in order to obtain callbacks
- * before and after each method invocation for a given class.
- * <p>
-
- * <p>[<a href="http://gee.cs.oswego.edu/dl/classes/EDU/oswego/cs/dl/util/concurrent/intro.html"> Introduction to this package. </a>]
- **/
-
-
- public interface Sync {
-
- /**
- * Wait (possibly forever) until successful passage.
- * Fail only upon interuption. Interruptions always result in
- * `clean' failures. On failure, you can be sure that it has not
- * been acquired, and that no
- * corresponding release should be performed. Conversely,
- * a normal return guarantees that the acquire was successful.
- **/
-
- public void acquire() throws InterruptedException;
-
- /**
- * Wait at most msecs to pass; report whether passed.
- * <p>
- * The method has best-effort semantics:
- * The msecs bound cannot
- * be guaranteed to be a precise upper bound on wait time in Java.
- * Implementations generally can only attempt to return as soon as possible
- * after the specified bound. Also, timers in Java do not stop during garbage
- * collection, so timeouts can occur just because a GC intervened.
- * So, msecs arguments should be used in
- * a coarse-grained manner. Further,
- * implementations cannot always guarantee that this method
- * will return at all without blocking indefinitely when used in
- * unintended ways. For example, deadlocks may be encountered
- * when called in an unintended context.
- * <p>
- * @param msecs the number of milleseconds to wait.
- * An argument less than or equal to zero means not to wait at all.
- * However, this may still require
- * access to a synchronization lock, which can impose unbounded
- * delay if there is a lot of contention among threads.
- * @return true if acquired
- **/
-
- public boolean attempt(long msecs) throws InterruptedException;
-
- /**
- * Potentially enable others to pass.
- * <p>
- * Because release does not raise exceptions,
- * it can be used in `finally' clauses without requiring extra
- * embedded try/catch blocks. But keep in mind that
- * as with any java method, implementations may
- * still throw unchecked exceptions such as Error or NullPointerException
- * when faced with uncontinuable errors. However, these should normally
- * only be caught by higher-level error handlers.
- **/
-
- public void release();
-
- /** One second, in milliseconds; convenient as a time-out value **/
- public static final long ONE_SECOND = 1000;
-
- /** One minute, in milliseconds; convenient as a time-out value **/
- public static final long ONE_MINUTE = 60 * ONE_SECOND;
-
- /** One hour, in milliseconds; convenient as a time-out value **/
- public static final long ONE_HOUR = 60 * ONE_MINUTE;
-
- /** One day, in milliseconds; convenient as a time-out value **/
- public static final long ONE_DAY = 24 * ONE_HOUR;
-
- /** One week, in milliseconds; convenient as a time-out value **/
- public static final long ONE_WEEK = 7 * ONE_DAY;
-
- /** One year in milliseconds; convenient as a time-out value **/
- // Not that it matters, but there is some variation across
- // standard sources about value at msec precision.
- // The value used is the same as in java.util.GregorianCalendar
- public static final long ONE_YEAR = (long)(365.2425 * ONE_DAY);
-
- /** One century in milliseconds; convenient as a time-out value **/
- public static final long ONE_CENTURY = 100 * ONE_YEAR;
-
-
- }
-
-