diff src/EDU/oswego/cs/dl/util/concurrent/Semaphore.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/Semaphore.java	Sat Mar 21 11:00:06 2009 +0000
@@ -0,0 +1,189 @@
+/*
+  File: Semaphore.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               replaced int counters with longs
+  24Aug1999  dl               release(n): screen arguments
+*/
+
+package EDU.oswego.cs.dl.util.concurrent;
+
+/**
+ * Base class for counting semaphores.
+ * Conceptually, a semaphore maintains a set of permits.
+ * Each acquire() blocks if necessary
+ * until a permit is available, and then takes it. 
+ * Each release adds a permit. However, no actual permit objects
+ * are used; the Semaphore just keeps a count of the number
+ * available and acts accordingly.
+ * <p>
+ * A semaphore initialized to 1 can serve as a mutual exclusion
+ * lock. 
+ * <p>
+ * Different implementation subclasses may provide different
+ * ordering guarantees (or lack thereof) surrounding which
+ * threads will be resumed upon a signal.
+ * <p>
+ * The default implementation makes NO 
+ * guarantees about the order in which threads will 
+ * acquire permits. It is often faster than other implementations.
+ * <p>
+ * <b>Sample usage.</b> Here is a class that uses a semaphore to
+ * help manage access to a pool of items.
+ * <pre>
+ * class Pool {
+ *   static final MAX_AVAILABLE = 100;
+ *   private final Semaphore available = new Semaphore(MAX_AVAILABLE);
+ *   
+ *   public Object getItem() throws InterruptedException { // no synch
+ *     available.acquire();
+ *     return getNextAvailableItem();
+ *   }
+ *
+ *   public void putItem(Object x) { // no synch
+ *     if (markAsUnused(x))
+ *       available.release();
+ *   }
+ *
+ *   // Not a particularly efficient data structure; just for demo
+ *
+ *   protected Object[] items = ... whatever kinds of items being managed
+ *   protected boolean[] used = new boolean[MAX_AVAILABLE];
+ *
+ *   protected synchronized Object getNextAvailableItem() { 
+ *     for (int i = 0; i < MAX_AVAILABLE; ++i) {
+ *       if (!used[i]) {
+ *          used[i] = true;
+ *          return items[i];
+ *       }
+ *     }
+ *     return null; // not reached 
+ *   }
+ *
+ *   protected synchronized boolean markAsUnused(Object item) { 
+ *     for (int i = 0; i < MAX_AVAILABLE; ++i) {
+ *       if (item == items[i]) {
+ *          if (used[i]) {
+ *            used[i] = false;
+ *            return true;
+ *          }
+ *          else
+ *            return false;
+ *       }
+ *     }
+ *     return false;
+ *   }
+ *
+ * }
+ *</pre>
+ * <p>[<a href="http://gee.cs.oswego.edu/dl/classes/EDU/oswego/cs/dl/util/concurrent/intro.html"> Introduction to this package. </a>]
+**/
+
+
+public class Semaphore implements Sync  {
+  /** current number of available permits **/
+  protected long permits_;
+
+  /** 
+   * Create a Semaphore with the given initial number of permits.
+   * Using a seed of one makes the semaphore act as a mutual exclusion lock.
+   * Negative seeds are also allowed, in which case no acquires will proceed
+   * until the number of releases has pushed the number of permits past 0.
+  **/
+  public Semaphore(long initialPermits) {  permits_ = initialPermits; }
+
+
+  /** Wait until a permit is available, and take one **/
+  public void acquire() throws InterruptedException {
+    if (Thread.interrupted()) throw new InterruptedException();
+    synchronized(this) {
+      try {
+        while (permits_ <= 0) wait();
+        --permits_;
+      }
+      catch (InterruptedException ex) {
+        notify();
+        throw ex;
+      }
+    }
+  }
+
+  /** Wait at most msecs millisconds for a permit. **/
+  public boolean attempt(long msecs) throws InterruptedException {
+    if (Thread.interrupted()) throw new InterruptedException();
+
+    synchronized(this) {
+      if (permits_ > 0) { 
+        --permits_;
+        return true;
+      }
+      else if (msecs <= 0)   
+        return false;
+      else {
+        try {
+          long startTime = System.currentTimeMillis();
+          long waitTime = msecs;
+          
+          for (;;) {
+            wait(waitTime);
+            if (permits_ > 0) {
+              --permits_;
+              return true;
+            }
+            else { 
+              waitTime = msecs - (System.currentTimeMillis() - startTime);
+              if (waitTime <= 0) 
+                return false;
+            }
+          }
+        }
+        catch(InterruptedException ex) { 
+          notify();
+          throw ex;
+        }
+      }
+    }
+  }
+
+  /** Release a permit **/
+  public synchronized void release() {
+    ++permits_;
+    notify();
+  }
+
+
+  /** 
+   * Release N permits. <code>release(n)</code> is
+   * equivalent in effect to:
+   * <pre>
+   *   for (int i = 0; i < n; ++i) release();
+   * </pre>
+   * <p>
+   * But may be more efficient in some semaphore implementations.
+   * @exception IllegalArgumentException if n is negative.
+   **/
+  public synchronized void release(long n) {
+    if (n < 0) throw new IllegalArgumentException("Negative argument");
+
+    permits_ += n;
+    for (long i = 0; i < n; ++i) notify();
+  }
+
+  /**
+   * Return the current number of available permits.
+   * Returns an accurate, but possibly unstable value,
+   * that may change immediately after returning.
+   **/
+  public synchronized long permits() {
+    return permits_;
+  }
+
+}
+