ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/main/java/util/concurrent/Locks.java
Revision: 1.2
Committed: Tue May 27 18:14:40 2003 UTC (21 years ago) by dl
Branch: MAIN
CVS Tags: JSR166_PRELIMINARY_TEST_RELEASE_1, JSR166_PRERELEASE_0_1
Changes since 1.1: +123 -80 lines
Log Message:
re-check-in initial implementations

File Contents

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