View Javadoc

1   /*
2    * Atlassian Source Code Template.
3    * User: Mike Cannon-Brookes
4    * Date: 31/07/2002
5    * Time: 19:33:40
6    * CVS Revision: $Revision: 1.1 $
7    * Last CVS Commit: $Date: 2002/12/02 05:26:32 $
8    * Author of last CVS Commit: $Author: mike $
9    *
10   * Originally written by Doug Lea and released into the public domain.
11   * This may be used for any purposes whatsoever without acknowledgment.
12   * Thanks for the assistance and support of Sun Microsystems Labs,
13   * and everyone contributing, testing, and using this code.
14   *
15   * History:
16   * Date       Who                What
17   * 11Jun1998  dl               Create public version
18   *  5Aug1998  dl               replaced int counters with longs
19   * 24Aug1999  dl               release(n): screen arguments
20   * 31Jul2002  mcb              borrowed from Jive 2.5.4(license above says we can do this)
21   */
22  package com.atlassian.core.util;
23  
24  
25  /**
26   * Base class for counting semaphores.
27   * Conceptually, a semaphore maintains a set of permits.
28   * Each acquire() blocks if necessary
29   * until a permit is available, and then takes it.
30   * Each release adds a permit. However, no actual permit objects
31   * are used; the Semaphore just keeps a count of the number
32   * available and acts accordingly.
33   * <p>
34   * A semaphore initialized to 1 can serve as a mutual exclusion
35   * lock.
36   * <p>
37   * Different implementation subclasses may provide different
38   * ordering guarantees (or lack thereof) surrounding which
39   * threads will be resumed upon a signal.
40   * <p>
41   * The default implementation makes NO
42   * guarantees about the order in which threads will
43   * acquire permits. It is often faster than other implementations.
44   */
45  public class Semaphore
46  {
47  
48      /** current number of available permits **/
49      protected long permits;
50  
51      /**
52       * Create a Semaphore with the given initial number of permits.
53       * Using a seed of one makes the semaphore act as a mutual exclusion lock.
54       * Negative seeds are also allowed, in which case no acquires will proceed
55       * until the number of releases has pushed the number of permits past 0.
56       */
57      public Semaphore(long initialPermits)
58      {
59          permits = initialPermits;
60      }
61  
62  
63      /**
64       * Wait until a permit is available, and take one
65       */
66      public void acquire() throws InterruptedException
67      {
68          if (Thread.interrupted())
69          {
70              throw new InterruptedException();
71          }
72  
73          synchronized (this)
74          {
75              try
76              {
77                  while (permits <= 0)
78                  {
79                      wait();
80                  }
81                  --permits;
82              }
83              catch (InterruptedException ex)
84              {
85                  notify();
86                  throw ex;
87              }
88          }
89      }
90  
91      /**
92       * Wait at most msecs millisconds for a permit.
93       */
94      public boolean attempt(long msecs) throws InterruptedException
95      {
96          if (Thread.interrupted())
97          {
98              throw new InterruptedException();
99          }
100 
101         synchronized (this)
102         {
103             if (permits > 0)
104             {
105                 --permits;
106                 return true;
107             }
108             else if (msecs <= 0)
109             {
110                 return false;
111             }
112             else
113             {
114                 try
115                 {
116                     long startTime = System.currentTimeMillis();
117                     long waitTime = msecs;
118 
119                     for (; ;)
120                     {
121                         wait(waitTime);
122                         if (permits > 0)
123                         {
124                             --permits;
125                             return true;
126                         }
127                         else
128                         {
129                             waitTime = msecs - (System.currentTimeMillis() - startTime);
130                             if (waitTime <= 0)
131                             {
132                                 return false;
133                             }
134                         }
135                     }
136                 }
137                 catch (InterruptedException ex)
138                 {
139                     notify();
140                     throw ex;
141                 }
142             }
143         }
144     }
145 
146     /**
147      * Release a permit
148      */
149     public synchronized void release()
150     {
151         ++permits;
152         notify();
153     }
154 
155 
156     /**
157      * Release N permits. <code>release(n)</code> is
158      * equivalent in effect to:
159      * <pre>
160      *   for (int i = 0; i < n; ++i) release();
161      * </pre>
162      * <p>
163      * But may be more efficient in some semaphore implementations.
164      *
165      * @exception IllegalArgumentException if n is negative.
166      */
167     public synchronized void release(long n)
168     {
169         if (n < 0)
170         {
171             throw new IllegalArgumentException("Negative argument");
172         }
173 
174         permits += n;
175 
176         for (long i = 0; i < n; ++i)
177         {
178             notify();
179         }
180     }
181 
182     /**
183      * Return the current number of available permits.
184      * Returns an accurate, but possibly unstable value,
185      * that may change immediately after returning.
186      */
187     public synchronized long permits()
188     {
189         return permits;
190     }
191 }