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, 10 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

# 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 java.util.Date;
9
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 * @revised $Date: 2003/06/24 14:34:48 $
56 * @editor $Author: dl $
57 * @author Doug Lea
58 *
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 if (lock == null || action == null)
84 throw new NullPointerException();
85
86 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 }
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 // 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 }
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 // 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 }
190
191 /**
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 * @param lock the object serving as a lock
196 * @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
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 * <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 * </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 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 }
332
333 }