ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/main/java/util/concurrent/Locks.java
Revision: 1.5
Committed: Tue Jul 8 00:46:34 2003 UTC (20 years, 11 months ago) by dl
Branch: MAIN
CVS Tags: HEAD
Changes since 1.4: +1 -1 lines
State: FILE REMOVED
Log Message:
Locks in subpackage; fairness params added

File Contents

# User Rev Content
1 dl 1.2 /*
2     * Written by Doug Lea with assistance from members of JCP JSR-166
3     * Expert Group and released to the public domain. Use, modify, and
4     * redistribute this code in any way without acknowledgement.
5     */
6    
7 tim 1.1 package java.util.concurrent;
8 dl 1.2 import java.util.Date;
9 tim 1.1
10     /**
11     * Utility operations for built-in synchronization and {@link Lock} classes.
12     * <p>The <tt>Locks</tt> class defines utility methods that enhance the
13     * use of <tt>synchronized</tt> methods and statements by:
14     * <ul>
15     * <li>allowing for an attempt to acquire a monitor lock only if it is free,
16     * <li>providing a method to acquire multiple monitor locks only if
17     * they are all available.
18     * </ul>
19     * <p>An additional convenience method is provided to acquire multiple
20     * {@link Lock} instances only if they are all available.
21     * <p>To preserve the block-structured locking that is required for the
22     * built-in monitor locks, each method takes a {@link Runnable} action as
23     * an argument and executes its {@link Runnable#run run} method with the
24     * appropriate locks held.
25     * When the {@link Runnable#run run} method completes all locks
26     * are released.
27     *
28     * <p><b>Note:</b> All methods that take {@link Object} parameters treat
29     * those parameters as {@link Object Objects}, even if they happen to be
30     * {@link Lock} instances. These methods will always acquire the monitor
31     * lock of the given object - they will not perform a {@link Lock#lock}
32     * invocation.
33     *
34     * <p>Except where noted, passing a <tt>null</tt> value for any parameter
35     * will result in a {@link NullPointerException} being thrown.
36     *
37     * <h3>Memory Synchronization</h3>
38     * <p>When a {@link Runnable} object's {@link Runnable#run run} method is
39     * executed it means that the appropriate
40     * lock (or locks) has been acquired, and so the memory synchronization
41     * effects of acquiring that lock will have taken place. Similarly, when
42     * the {@link Runnable} object's {@link Runnable#run run} method completes,
43     * the lock (or locks) is released and the associated memory synchronization
44     * effects will take place. Exactly what those memory synchronization
45     * effects are will depend on the nature of the lock and the type of
46     * acquisition/release - for example, reentrantly acquiring a monitor lock
47     * has no associated memory synchronization effects.
48     * <p>When mutliple locks are involved it may be that some of the locks are
49     * acquired and subsequently released, before an unavailable lock is found.
50     * In that case the memory synchronization effects will be those of the locks
51     * that were actually acquired and actually released.
52     *
53     * @since 1.5
54     * @spec JSR-166
55 dl 1.5 * @revised $Date: 2003/06/24 14:34:48 $
56 dl 1.3 * @editor $Author: dl $
57 dl 1.4 * @author Doug Lea
58 tim 1.1 *
59     **/
60     public class Locks {
61     private Locks() {} // uninstantiable.
62    
63     /**
64     * Performs the given action holding the monitor lock of
65     * the given object only if that lock is currently free.
66     *
67     * <p>If the monitor lock of the given object is immediately available
68     * to the current thread then it is acquired.
69     * The action is then executed and finally the monitor lock is released
70     * and the method returns with the value <tt>true</tt>.
71     * <p>If the monitor lock is not available then the method returns
72     * immediately with the value <tt>false</tt>.
73     * <p>If the action completes abruptly due to an {@link Error} or
74     * {@link RuntimeException}, then the method completes abruptly
75     * for the same reason, after the lock has been released.
76     *
77     * @param lock the object whose monitor lock must be acquired
78     * @param action the code to run while holding the monitor lock
79     * @return <tt>true</tt> if the action was executed, and <tt>false</tt>
80     * otherwise.
81     **/
82     public static boolean attempt(Object lock, Runnable action) {
83 dl 1.2 if (lock == null || action == null)
84     throw new NullPointerException();
85 tim 1.1
86 dl 1.2 if (!JSR166Support.tryLockEnter(lock))
87     return false;
88    
89     try {
90     action.run();
91     return true;
92     }
93     finally {
94     JSR166Support.tryLockExit(lock);
95     }
96 tim 1.1 }
97    
98     /**
99     * Performs the given action holding the monitor locks of
100     * the given objects only if those locks are currently free.
101     *
102     * <p>If the monitor locks of each object in the array are immediately
103     * available to the current thread then they are acquired.
104     * The action is then executed and finally the monitor locks are released
105     * and the method returns with the value <tt>true</tt>.
106     * <p>If any of the monitor locks is not available then
107     * all previously acquired monitor locks are released and the method
108     * returns with the value <tt>false</tt>.
109     * <p>If the action completes abruptly due to an {@link Error} or
110     * {@link RuntimeException}, then the method completes abruptly
111     * for the same reason, after all the locks have been released.
112     *
113     * @param locks the objects whose monitor locks must be acquired
114     * @param action the code to run while holding the monitor locks
115     * @return <tt>true</tt> if the action was executed, and <tt>false</tt>
116     * otherwise.
117     *
118     * @throws NullPointerException if an attempt is made to acquire the
119     * monitor lock of a <tt>null</tt> element in the <tt>locks</tt> array.
120     **/
121     public static boolean attempt(Object[] locks, Runnable action) {
122 dl 1.2 // This code is a little mysterious looking unless you remember
123     // that finally clauses execute before return or throw.
124     int lastlocked = -1;
125     try {
126     boolean ok = true;
127     for (int i = 0; i < locks.length; ++i) {
128     Object l = locks[i];
129     if (l == null)
130     throw new NullPointerException();
131     if (!JSR166Support.tryLockEnter(l))
132     return false;
133     lastlocked = i;
134     }
135     action.run();
136     return true;
137     }
138     finally {
139     for (int i = lastlocked; i >= 0; --i)
140     JSR166Support.tryLockExit(locks[i]);
141     }
142 tim 1.1 }
143    
144     /**
145     * Performs the given action holding the given {@link Lock} instances, only
146     * if those {@link Lock} instances are currently free.
147     *
148     * <p>If each of the locks in the array are immediately
149     * available to the current thread then they are acquired.
150     * The action is then executed and finally the locks are
151     * released and the method returns with the value <tt>true</tt>.
152     * <p>If any of the locks are not available then
153     * all previously acquired locks are released and the
154     * method returns immediately with the value <tt>false</tt>.
155     * <p>If the action completes abruptly due to an {@link Error} or
156     * {@link RuntimeException}, then the method completes abruptly
157     * for the same reason, after all the locks have been
158     * released.
159     *
160     * @param locks the {@link Lock} instances that must be acquired
161     * @param action the code to run while holding the given locks
162     * @return <tt>true</tt> if the action was executed, and <tt>false</tt>
163     * otherwise.
164     *
165     * @throws NullPointerException if an attempt is made to acquire the
166     * lock of a <tt>null</tt> element in the <tt>locks</tt> array.
167     **/
168     public static boolean attempt(Lock[] locks, Runnable action) {
169 dl 1.2 // This code is a little mysterious looking unless you remember
170     // that finally clauses execute before return or throw.
171     int lastlocked = -1;
172     try {
173     for (int i = 0; i < locks.length; ++i) {
174     Lock l = locks[i];
175     if (l == null)
176     throw new NullPointerException();
177     if (!l.tryLock())
178     return false;
179     lastlocked = i;
180     }
181    
182     action.run();
183     return true;
184     }
185     finally {
186     for (int i = lastlocked; i >= 0; --i)
187     locks[i].unlock();
188     }
189 tim 1.1 }
190    
191 dl 1.2 /**
192     * Returns a conservative indicator of whether the given lock is
193     * held by any thread. This method always returns true if
194     * the lock is held, but may return true even if not held.
195 dl 1.4 * @param lock the object serving as a lock
196 dl 1.2 * @return true if lock is held, and either true or false if not held.
197     */
198     public static boolean mightBeLocked(Object lock) {
199     return JSR166Support.mightBeLocked(lock);
200     }
201 tim 1.1
202     /**
203     * Returns a {@link Condition} instance for use with the given object.
204     * <p>The returned {@link Condition} instance has analagous behavior
205     * to the use of the monitor methods on the given object. Given
206     * <pre> Condition c = Locks.newConditionFor(o);
207     * </pre>
208     * then:
209     * <ul>
210 dl 1.2 * <li><tt>c.await()</tt> is analogous to <tt>o.wait()</tt>
211     * <li><tt>c.signal()</tt> is analogous to <tt>o.notify()</tt>; and
212     * <li><tt>c.signalAll()</tt> is analogous to <tt>o.notifyAll()</tt>
213 tim 1.1 * </ul>
214     * in that:
215     * <ul>
216     * <li>If the monitor lock of <tt>o</tt> is not held when any of the
217     * {@link Condition}
218     * {@link Condition#await() waiting} or {@link Condition#signal signalling}
219     * methods are called, then an {@link IllegalMonitorStateException} is
220     * thrown.
221     * <li>When the condition {@link Condition#await() waiting} methods are
222     * called the monitor lock of <tt>o</tt> is released and before they
223     * return the monitor lock is
224     * reacquired and the lock count restored to what it was when the
225     * method was called.
226     * <li>If a thread is {@link Thread#interrupt interrupted} while waiting
227     * then the wait will terminate, an {@link InterruptedException} will be
228     * thrown, and the thread's interrupted status will be cleared.
229     * <li>The order in which waiting threads are signalled is not specified.
230     * <li>The order in which threads returning from await, and threads trying
231     * to acquire the monitor lock, are granted the lock, is not specified.
232     * </ul>
233     * <p>A {@link Condition} instance obtained in this way can be used to
234     * create the
235     * affect of having additional monitor wait-sets for the given object.
236     * For example, suppose we have a bounded buffer which supports methods
237     * to <tt>put</tt> and <tt>take</tt> items in/from the buffer. If a
238     * <tt>take</tt> is attempted on an empty buffer then the thread will block
239     * until an item becomes available; if a <tt>put</tt> is attempted on a
240     * full buffer, then the thread will block until a space becomes available.
241     * We would like to keep waiting <tt>put</tt> threads and <tt>take</tt>
242     * threads in separate wait-sets so that we can use the optimisation of
243     * only notifying a single thread at a time when items, or spaces, become
244     * available in the buffer. This can be achieved using either two
245     * {@link Condition} instances, or one {@link Condition} instance and the
246     * actual
247     * monitor wait-set. For clarity we'll use two {@link Condition} instances.
248     * <pre><code>
249     * class BoundedBuffer {
250     * <b>final Condition notFull = Locks.newConditionFor(this);
251     * final Condition notEmpty = Locks.newConditionFor(this); </b>
252     *
253     * Object[] items = new Object[100];
254     * int putptr, takeptr, count;
255     *
256     * public <b>synchronized</b> void put(Object x)
257     * throws InterruptedException {
258     * while (count == items.length)
259     * <b>notFull.await();</b>
260     * items[putptr] = x;
261     * if (++putptr == items.length) putptr = 0;
262     * ++count;
263     * <b>notEmpty.signal();</b>
264     * }
265     *
266     * public <b>synchronized</b> Object take() throws InterruptedException {
267     * while (count == 0)
268     * <b>notEmpty.await();</b>
269     * Object x = items[takeptr];
270     * if (++takeptr == items.length) takeptr = 0;
271     * --count;
272     * <b>notFull.signal();</b>
273     * return x;
274     * }
275     * }
276     * </code></pre>
277     *
278     * @param lock the object that will be used for its monitor lock and to
279     * which the returned condition should be bound.
280     * @return a {@link Condition} instance bound to the given object
281     **/
282     public static Condition newConditionFor(Object lock) {
283 dl 1.2 return new ConditionObject(lock);
284     }
285    
286     static final private class ConditionObject implements Condition {
287     private final Object lock;
288     private final Object cond = new Object();
289    
290     ConditionObject(Object lock) { this.lock = lock; }
291    
292     public void await() throws InterruptedException {
293     JSR166Support.conditionWait(lock, cond);
294     }
295    
296     public void awaitUninterruptibly() {
297     boolean wasInterrupted = Thread.interrupted(); // record and clear
298     for (;;) {
299     try {
300     JSR166Support.conditionWait(lock, cond);
301     break;
302     }
303     catch (InterruptedException ex) { // re-interrupted; try again
304     wasInterrupted = true;
305     }
306     }
307     if (wasInterrupted) { // re-establish interrupted state
308     Thread.currentThread().interrupt();
309     }
310     }
311    
312     public long awaitNanos(long nanos) throws InterruptedException {
313     return JSR166Support.conditionRelWait(lock, cond, nanos);
314     }
315    
316     public boolean await(long time, TimeUnit unit) throws InterruptedException {
317     return awaitNanos(unit.toNanos(time)) > 0;
318     }
319    
320     public boolean awaitUntil(Date deadline) throws InterruptedException {
321     return JSR166Support.conditionAbsWait(lock, cond,
322     deadline.getTime());
323     }
324     public void signal() {
325     JSR166Support.conditionNotify(lock, cond);
326     }
327    
328     public void signalAll() {
329     JSR166Support.conditionNotifyAll(lock, cond);
330     }
331 tim 1.1 }
332    
333     }