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 |
} |