diff src/EDU/oswego/cs/dl/util/concurrent/Sync.java @ 0:3dc0c5604566

Initial checkin of blitz 2.0 fcs - no installer yet.
author Dan Creswell <dan.creswell@gmail.com>
date Sat, 21 Mar 2009 11:00:06 +0000
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/EDU/oswego/cs/dl/util/concurrent/Sync.java	Sat Mar 21 11:00:06 2009 +0000
@@ -0,0 +1,340 @@
+/*
+  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 EDU.oswego.cs.dl.util.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;
+
+
+}
+
+