1 |
tim |
1.1 |
package java.util.concurrent; |
2 |
|
|
|
3 |
|
|
|
4 |
|
|
/** |
5 |
|
|
* Utility operations for built-in synchronization and {@link Lock} classes. |
6 |
|
|
* <p>The <tt>Locks</tt> class defines utility methods that enhance the |
7 |
|
|
* use of <tt>synchronized</tt> methods and statements by: |
8 |
|
|
* <ul> |
9 |
|
|
* <li>allowing for an attempt to acquire a monitor lock only if it is free, |
10 |
|
|
* or if it becomes free within a specified time; |
11 |
|
|
* <li>allowing an attempt to acquire a monitor lock to be interruptible; and |
12 |
|
|
* <li>providing a method to acquire multiple monitor locks only if |
13 |
|
|
* they are all available. |
14 |
|
|
* </ul> |
15 |
|
|
* <p>An additional convenience method is provided to acquire multiple |
16 |
|
|
* {@link Lock} instances only if they are all available. |
17 |
|
|
* <p>To preserve the block-structured locking that is required for the |
18 |
|
|
* built-in monitor locks, each method takes a {@link Runnable} action as |
19 |
|
|
* an argument and executes its {@link Runnable#run run} method with the |
20 |
|
|
* appropriate locks held. |
21 |
|
|
* When the {@link Runnable#run run} method completes all locks |
22 |
|
|
* are released. |
23 |
|
|
* |
24 |
|
|
* <p><b>Note:</b> All methods that take {@link Object} parameters treat |
25 |
|
|
* those parameters as {@link Object Objects}, even if they happen to be |
26 |
|
|
* {@link Lock} instances. These methods will always acquire the monitor |
27 |
|
|
* lock of the given object - they will not perform a {@link Lock#lock} |
28 |
|
|
* invocation. |
29 |
|
|
* |
30 |
|
|
* <p>Except where noted, passing a <tt>null</tt> value for any parameter |
31 |
|
|
* will result in a {@link NullPointerException} being thrown. |
32 |
|
|
* |
33 |
|
|
* <h3>Memory Synchronization</h3> |
34 |
|
|
* <p>When a {@link Runnable} object's {@link Runnable#run run} method is |
35 |
|
|
* executed it means that the appropriate |
36 |
|
|
* lock (or locks) has been acquired, and so the memory synchronization |
37 |
|
|
* effects of acquiring that lock will have taken place. Similarly, when |
38 |
|
|
* the {@link Runnable} object's {@link Runnable#run run} method completes, |
39 |
|
|
* the lock (or locks) is released and the associated memory synchronization |
40 |
|
|
* effects will take place. Exactly what those memory synchronization |
41 |
|
|
* effects are will depend on the nature of the lock and the type of |
42 |
|
|
* acquisition/release - for example, reentrantly acquiring a monitor lock |
43 |
|
|
* has no associated memory synchronization effects. |
44 |
|
|
* <p>When mutliple locks are involved it may be that some of the locks are |
45 |
|
|
* acquired and subsequently released, before an unavailable lock is found. |
46 |
|
|
* In that case the memory synchronization effects will be those of the locks |
47 |
|
|
* that were actually acquired and actually released. |
48 |
|
|
* |
49 |
|
|
* @since 1.5 |
50 |
|
|
* @spec JSR-166 |
51 |
|
|
* @revised $Date: 2003/01/09 17:56:51 $ |
52 |
|
|
* @editor $Author: dl $ |
53 |
|
|
* |
54 |
|
|
* @fixme add implementation notes for any performance issues related to |
55 |
|
|
* timeouts or interrupts |
56 |
|
|
**/ |
57 |
|
|
public class Locks { |
58 |
|
|
|
59 |
|
|
private Locks() {} // uninstantiable. |
60 |
|
|
|
61 |
|
|
/** |
62 |
|
|
* Performs the given action holding the monitor lock of |
63 |
|
|
* the given object only if that lock is currently free. |
64 |
|
|
* |
65 |
|
|
* <p>If the monitor lock of the given object is immediately available |
66 |
|
|
* to the current thread then it is acquired. |
67 |
|
|
* The action is then executed and finally the monitor lock is released |
68 |
|
|
* and the method returns with the value <tt>true</tt>. |
69 |
|
|
* <p>If the monitor lock is not available then the method returns |
70 |
|
|
* immediately with the value <tt>false</tt>. |
71 |
|
|
* <p>If the action completes abruptly due to an {@link Error} or |
72 |
|
|
* {@link RuntimeException}, then the method completes abruptly |
73 |
|
|
* for the same reason, after the lock has been released. |
74 |
|
|
* |
75 |
|
|
* @param lock the object whose monitor lock must be acquired |
76 |
|
|
* @param action the code to run while holding the monitor lock |
77 |
|
|
* @return <tt>true</tt> if the action was executed, and <tt>false</tt> |
78 |
|
|
* otherwise. |
79 |
|
|
**/ |
80 |
|
|
public static boolean attempt(Object lock, Runnable action) { |
81 |
|
|
return false; // for now; |
82 |
|
|
} |
83 |
|
|
|
84 |
|
|
/** |
85 |
|
|
* Performs the given action holding the monitor lock of |
86 |
|
|
* the given object if it is free within the given waiting time and the |
87 |
|
|
* current thread has not been {@link Thread#interrupt interrupted}. |
88 |
|
|
* |
89 |
|
|
* <p>If the monitor lock of the given object is immediately available |
90 |
|
|
* to the current thread then it is acquired. |
91 |
|
|
* The action is then executed and finally the monitor lock is released |
92 |
|
|
* and the method returns with the value <tt>true</tt>. |
93 |
|
|
* |
94 |
|
|
* <p>If the monitor lock is not available then |
95 |
|
|
* the current thread becomes disabled for thread scheduling |
96 |
|
|
* purposes and lies dormant until one of three things happens: |
97 |
|
|
* <ul> |
98 |
|
|
* <li> The monitor lock is acquired by the current thread; or |
99 |
|
|
* <li> Some other thread {@link Thread#interrupt interrupts} the current |
100 |
|
|
* thread; or |
101 |
|
|
* <li> The specified waiting time elapses |
102 |
|
|
* </ul> |
103 |
|
|
* <p>If the monitor lock is acquired |
104 |
|
|
* the action is executed then the monitor lock is released |
105 |
|
|
* and the method returns with the value <tt>true</tt>. |
106 |
|
|
* |
107 |
|
|
* <p>If the action completes abruptly due to an {@link Error} or |
108 |
|
|
* {@link RuntimeException}, then the method completes abruptly |
109 |
|
|
* for the same reason, after the lock has been released. |
110 |
|
|
* |
111 |
|
|
* <p>If the current thread: |
112 |
|
|
* <ul> |
113 |
|
|
* <li>has its interrupted status set on entry to this method; or |
114 |
|
|
* <li>is {@link Thread#interrupt interrupted} while waiting to acquire |
115 |
|
|
* the monitor lock, |
116 |
|
|
* </ul> |
117 |
|
|
* then {@link InterruptedException} is thrown and the current thread's |
118 |
|
|
* interrupted status is cleared. |
119 |
|
|
* |
120 |
|
|
* <p>If the specified waiting time elapses then the value <tt>false</tt> |
121 |
|
|
* is returned. |
122 |
|
|
* The given waiting time is a best-effort lower bound. If the time is |
123 |
|
|
* less than or equal to zero, the method will not wait at all. |
124 |
|
|
* |
125 |
|
|
* <p><b>Implementation Notes</b> |
126 |
|
|
* <p>TO-BE-DONE |
127 |
|
|
* |
128 |
|
|
* |
129 |
|
|
* @param lock the object whose monitor lock must be acquired |
130 |
|
|
* @param action the code to run while holding the monitor lock |
131 |
|
|
* @param timeout the maximum time to wait for the monitor lock |
132 |
|
|
* @param granularity the time unit of the <tt>timeout</tt> argument. |
133 |
|
|
* @return <tt>true</tt> if the monitor lock was acquired and the |
134 |
|
|
* action executed, and <tt>false</tt> |
135 |
|
|
* if the waiting time elapsed before the monitor lock was acquired. |
136 |
|
|
* |
137 |
|
|
* @throws InterruptedException if the current thread is interrupted |
138 |
|
|
* while trying to acquire the monitor lock. |
139 |
|
|
* |
140 |
|
|
* @see Thread#interrupt |
141 |
|
|
* |
142 |
|
|
**/ |
143 |
|
|
public static boolean attempt(Object lock, Runnable action, |
144 |
|
|
long timeout, TimeUnit granularity) |
145 |
|
|
throws InterruptedException { |
146 |
|
|
|
147 |
|
|
return false; // for now; |
148 |
|
|
} |
149 |
|
|
|
150 |
|
|
/** |
151 |
|
|
* Performs the given action holding the monitor locks of |
152 |
|
|
* the given objects only if those locks are currently free. |
153 |
|
|
* |
154 |
|
|
* <p>If the monitor locks of each object in the array are immediately |
155 |
|
|
* available to the current thread then they are acquired. |
156 |
|
|
* The action is then executed and finally the monitor locks are released |
157 |
|
|
* and the method returns with the value <tt>true</tt>. |
158 |
|
|
* <p>If any of the monitor locks is not available then |
159 |
|
|
* all previously acquired monitor locks are released and the method |
160 |
|
|
* returns with the value <tt>false</tt>. |
161 |
|
|
* <p>If the action completes abruptly due to an {@link Error} or |
162 |
|
|
* {@link RuntimeException}, then the method completes abruptly |
163 |
|
|
* for the same reason, after all the locks have been released. |
164 |
|
|
* |
165 |
|
|
* @param locks the objects whose monitor locks must be acquired |
166 |
|
|
* @param action the code to run while holding the monitor locks |
167 |
|
|
* @return <tt>true</tt> if the action was executed, and <tt>false</tt> |
168 |
|
|
* otherwise. |
169 |
|
|
* |
170 |
|
|
* @throws NullPointerException if an attempt is made to acquire the |
171 |
|
|
* monitor lock of a <tt>null</tt> element in the <tt>locks</tt> array. |
172 |
|
|
**/ |
173 |
|
|
public static boolean attempt(Object[] locks, Runnable action) { |
174 |
|
|
return false; // for now; |
175 |
|
|
} |
176 |
|
|
|
177 |
|
|
/** |
178 |
|
|
* Performs the given action holding the given {@link Lock} instances, only |
179 |
|
|
* if those {@link Lock} instances are currently free. |
180 |
|
|
* |
181 |
|
|
* <p>If each of the locks in the array are immediately |
182 |
|
|
* available to the current thread then they are acquired. |
183 |
|
|
* The action is then executed and finally the locks are |
184 |
|
|
* released and the method returns with the value <tt>true</tt>. |
185 |
|
|
* <p>If any of the locks are not available then |
186 |
|
|
* all previously acquired locks are released and the |
187 |
|
|
* method returns immediately with the value <tt>false</tt>. |
188 |
|
|
* <p>If the action completes abruptly due to an {@link Error} or |
189 |
|
|
* {@link RuntimeException}, then the method completes abruptly |
190 |
|
|
* for the same reason, after all the locks have been |
191 |
|
|
* released. |
192 |
|
|
* |
193 |
|
|
* @param locks the {@link Lock} instances that must be acquired |
194 |
|
|
* @param action the code to run while holding the given locks |
195 |
|
|
* @return <tt>true</tt> if the action was executed, and <tt>false</tt> |
196 |
|
|
* otherwise. |
197 |
|
|
* |
198 |
|
|
* @throws NullPointerException if an attempt is made to acquire the |
199 |
|
|
* lock of a <tt>null</tt> element in the <tt>locks</tt> array. |
200 |
|
|
**/ |
201 |
|
|
public static boolean attempt(Lock[] locks, Runnable action) { |
202 |
|
|
return false; // for now; |
203 |
|
|
} |
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 analagous to <tt>o.wait()</tt> |
215 |
|
|
* <li><tt>c.signal()</tt> is analagous to <tt>o.notify()</tt>; and |
216 |
|
|
* <li><tt>c.signalAll()</tt> is analagous 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 null; // for now; |
288 |
|
|
} |
289 |
|
|
|
290 |
|
|
} |
291 |
|
|
|
292 |
|
|
|
293 |
|
|
|
294 |
|
|
|