1 |
< |
package java.util.concurrent; |
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. |
62 |
|
* timeouts or interrupts |
63 |
|
**/ |
64 |
|
public class Locks { |
58 |
– |
|
65 |
|
private Locks() {} // uninstantiable. |
66 |
|
|
67 |
|
/** |
84 |
|
* otherwise. |
85 |
|
**/ |
86 |
|
public static boolean attempt(Object lock, Runnable action) { |
87 |
< |
return false; // for now; |
88 |
< |
} |
87 |
> |
if (lock == null || action == null) |
88 |
> |
throw new NullPointerException(); |
89 |
|
|
90 |
< |
/** |
91 |
< |
* Performs the given action holding the monitor lock of |
92 |
< |
* the given object if it is free within the given waiting time and the |
93 |
< |
* current thread has not been {@link Thread#interrupt interrupted}. |
94 |
< |
* |
95 |
< |
* <p>If the monitor lock of the given object is immediately available |
96 |
< |
* to the current thread then it is acquired. |
97 |
< |
* The action is then executed and finally the monitor lock is released |
98 |
< |
* and the method returns with the value <tt>true</tt>. |
99 |
< |
* |
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; |
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 |
|
/** |
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 |
< |
return false; // for now; |
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 |
|
/** |
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 |
< |
return false; // for now; |
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. |
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> |
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> |
284 |
|
* @return a {@link Condition} instance bound to the given object |
285 |
|
**/ |
286 |
|
public static Condition newConditionFor(Object lock) { |
287 |
< |
return null; // for now; |
287 |
> |
return new ConditionObject(lock); |
288 |
|
} |
289 |
|
|
290 |
< |
} |
291 |
< |
|
292 |
< |
|
293 |
< |
|
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 |
+ |
} |