1 |
/* |
2 |
* Written by Doug Lea with assistance from members of JCP JSR-166 |
3 |
* Expert Group and released to the public domain, as explained at |
4 |
* http://creativecommons.org/publicdomain/zero/1.0/ |
5 |
*/ |
6 |
|
7 |
package jsr166e; |
8 |
import java.util.concurrent.TimeUnit; |
9 |
import java.util.concurrent.TimeoutException; |
10 |
import java.util.concurrent.locks.Lock; |
11 |
import java.util.concurrent.locks.ReentrantLock; |
12 |
import java.util.concurrent.locks.Condition; |
13 |
import java.util.concurrent.locks.AbstractQueuedLongSynchronizer; |
14 |
import java.util.Collection; |
15 |
import java.io.ObjectOutputStream; |
16 |
import java.io.ObjectInputStream; |
17 |
import java.io.IOException; |
18 |
|
19 |
/** |
20 |
* A reentrant mutual exclusion {@link Lock} in which each lock |
21 |
* acquisition or release advances a sequence number. When the |
22 |
* sequence number (accessible using {@link #getSequence()}) is odd, |
23 |
* the lock is held. When it is even (i.e., ({@code lock.getSequence() |
24 |
* & 1L) == 0L}), the lock is released. Method {@link |
25 |
* #awaitAvailability} can be used to await availability of the lock, |
26 |
* returning its current sequence number. Sequence numbers (as well as |
27 |
* reentrant hold counts) are of type {@code long} to ensure that they |
28 |
* will not wrap around until hundreds of years of use under current |
29 |
* processor rates. A SequenceLock can be created with a specified |
30 |
* number of spins. Attempts to acquire the lock in method {@link |
31 |
* #lock} will retry at least the given number of times before |
32 |
* blocking. If not specified, a default, possibly platform-specific, |
33 |
* value is used. |
34 |
* |
35 |
* <p>Except for the lack of support for specified fairness policies, |
36 |
* or {@link Condition} objects, a SequenceLock can be used in the |
37 |
* same way as {@link ReentrantLock}. It provides similar status and |
38 |
* monitoring methods, such as {@link #isHeldByCurrentThread}. |
39 |
* SequenceLocks may be preferable in contexts in which multiple |
40 |
* threads invoke short read-only methods much more frequently than |
41 |
* fully locked methods. |
42 |
* |
43 |
* <p> Methods {@code awaitAvailability} and {@code getSequence} can |
44 |
* be used together to define (partially) optimistic read-only methods |
45 |
* that are usually more efficient than ReadWriteLocks when they |
46 |
* apply. These methods should in general be structured as loops that |
47 |
* await lock availability, then read {@code volatile} fields into |
48 |
* local variables (and may further read other values derived from |
49 |
* these, for example the {@code length} of a {@code volatile} array), |
50 |
* and retry if the sequence number changed while doing so. |
51 |
* Alternatively, because {@code awaitAvailability} accommodates |
52 |
* reentrancy, a method can retry a bounded number of times before |
53 |
* switching to locking mode. While conceptually straightforward, |
54 |
* expressing these ideas can be verbose. For example: |
55 |
* |
56 |
* <pre> {@code |
57 |
* class Point { |
58 |
* private volatile double x, y; |
59 |
* private final SequenceLock sl = new SequenceLock(); |
60 |
* |
61 |
* // an exclusively locked method |
62 |
* void move(double deltaX, double deltaY) { |
63 |
* sl.lock(); |
64 |
* try { |
65 |
* x += deltaX; |
66 |
* y += deltaY; |
67 |
* } finally { |
68 |
* sl.unlock(); |
69 |
* } |
70 |
* } |
71 |
* |
72 |
* // A read-only method |
73 |
* double distanceFromOriginV1() { |
74 |
* double currentX, currentY; |
75 |
* long seq; |
76 |
* do { |
77 |
* seq = sl.awaitAvailability(); |
78 |
* currentX = x; |
79 |
* currentY = y; |
80 |
* } while (sl.getSequence() != seq); // retry if sequence changed |
81 |
* return Math.sqrt(currentX * currentX + currentY * currentY); |
82 |
* } |
83 |
* |
84 |
* // Uses bounded retries before locking |
85 |
* double distanceFromOriginV2() { |
86 |
* double currentX, currentY; |
87 |
* long seq; |
88 |
* int retries = RETRIES_BEFORE_LOCKING; // for example 8 |
89 |
* try { |
90 |
* do { |
91 |
* if (--retries < 0) |
92 |
* sl.lock(); |
93 |
* seq = sl.awaitAvailability(); |
94 |
* currentX = x; |
95 |
* currentY = y; |
96 |
* } while (sl.getSequence() != seq); |
97 |
* } finally { |
98 |
* if (retries < 0) |
99 |
* sl.unlock(); |
100 |
* } |
101 |
* return Math.sqrt(currentX * currentX + currentY * currentY); |
102 |
* } |
103 |
* }}</pre> |
104 |
* |
105 |
* @since 1.8 |
106 |
* @author Doug Lea |
107 |
*/ |
108 |
public class SequenceLock implements Lock, java.io.Serializable { |
109 |
private static final long serialVersionUID = 7373984872572414699L; |
110 |
|
111 |
static final class Sync extends AbstractQueuedLongSynchronizer { |
112 |
static final long serialVersionUID = 2540673546047039555L; |
113 |
|
114 |
/** |
115 |
* The number of times to spin in lock() and awaitAvailability(). |
116 |
*/ |
117 |
final int spins; |
118 |
|
119 |
/** |
120 |
* The number of reentrant holds on this lock. Uses a long for |
121 |
* compatibility with other AbstractQueuedLongSynchronizer |
122 |
* operations. Accessed only by lock holder. |
123 |
*/ |
124 |
long holds; |
125 |
|
126 |
Sync(int spins) { this.spins = spins; } |
127 |
|
128 |
// overrides of AQLS methods |
129 |
|
130 |
public final boolean isHeldExclusively() { |
131 |
return (getState() & 1L) != 0L && |
132 |
getExclusiveOwnerThread() == Thread.currentThread(); |
133 |
} |
134 |
|
135 |
public final boolean tryAcquire(long acquires) { |
136 |
Thread current = Thread.currentThread(); |
137 |
long c = getState(); |
138 |
if ((c & 1L) == 0L) { |
139 |
if (compareAndSetState(c, c + 1L)) { |
140 |
holds = acquires; |
141 |
setExclusiveOwnerThread(current); |
142 |
return true; |
143 |
} |
144 |
} |
145 |
else if (current == getExclusiveOwnerThread()) { |
146 |
holds += acquires; |
147 |
return true; |
148 |
} |
149 |
return false; |
150 |
} |
151 |
|
152 |
public final boolean tryRelease(long releases) { |
153 |
if (Thread.currentThread() != getExclusiveOwnerThread()) |
154 |
throw new IllegalMonitorStateException(); |
155 |
if ((holds -= releases) == 0L) { |
156 |
setExclusiveOwnerThread(null); |
157 |
setState(getState() + 1L); |
158 |
return true; |
159 |
} |
160 |
return false; |
161 |
} |
162 |
|
163 |
public final long tryAcquireShared(long unused) { |
164 |
return (((getState() & 1L) == 0L) ? 1L : |
165 |
(getExclusiveOwnerThread() == Thread.currentThread()) ? 0L: |
166 |
-1L); |
167 |
} |
168 |
|
169 |
public final boolean tryReleaseShared(long unused) { |
170 |
return (getState() & 1L) == 0L; |
171 |
} |
172 |
|
173 |
public final Condition newCondition() { |
174 |
throw new UnsupportedOperationException(); |
175 |
} |
176 |
|
177 |
// Other methods in support of SequenceLock |
178 |
|
179 |
final long getSequence() { |
180 |
return getState(); |
181 |
} |
182 |
|
183 |
final void lock() { |
184 |
int k = spins; |
185 |
while (!tryAcquire(1L)) { |
186 |
if (k == 0) { |
187 |
acquire(1L); |
188 |
break; |
189 |
} |
190 |
--k; |
191 |
} |
192 |
} |
193 |
|
194 |
final long awaitAvailability() { |
195 |
long s; |
196 |
while (((s = getState()) & 1L) != 0L && |
197 |
getExclusiveOwnerThread() != Thread.currentThread()) { |
198 |
acquireShared(1L); |
199 |
releaseShared(1L); |
200 |
} |
201 |
return s; |
202 |
} |
203 |
|
204 |
final long tryAwaitAvailability(long nanos) |
205 |
throws InterruptedException, TimeoutException { |
206 |
Thread current = Thread.currentThread(); |
207 |
for (;;) { |
208 |
long s = getState(); |
209 |
if ((s & 1L) == 0L || getExclusiveOwnerThread() == current) { |
210 |
releaseShared(1L); |
211 |
return s; |
212 |
} |
213 |
if (!tryAcquireSharedNanos(1L, nanos)) |
214 |
throw new TimeoutException(); |
215 |
// since tryAcquireSharedNanos doesn't return seq |
216 |
// retry with minimal wait time. |
217 |
nanos = 1L; |
218 |
} |
219 |
} |
220 |
|
221 |
final boolean isLocked() { |
222 |
return (getState() & 1L) != 0L; |
223 |
} |
224 |
|
225 |
final Thread getOwner() { |
226 |
return (getState() & 1L) == 0L ? null : getExclusiveOwnerThread(); |
227 |
} |
228 |
|
229 |
final long getHoldCount() { |
230 |
return isHeldExclusively() ? holds : 0; |
231 |
} |
232 |
|
233 |
private void readObject(ObjectInputStream s) |
234 |
throws IOException, ClassNotFoundException { |
235 |
s.defaultReadObject(); |
236 |
holds = 0L; |
237 |
setState(0L); // reset to unlocked state |
238 |
} |
239 |
} |
240 |
|
241 |
private final Sync sync; |
242 |
|
243 |
/** |
244 |
* The default spin value for constructor. Future versions of this |
245 |
* class might choose platform-specific values. Currently, except |
246 |
* on uniprocessors, it is set to a small value that overcomes near |
247 |
* misses between releases and acquires. |
248 |
*/ |
249 |
static final int DEFAULT_SPINS = |
250 |
Runtime.getRuntime().availableProcessors() > 1 ? 64 : 0; |
251 |
|
252 |
/** |
253 |
* Creates an instance of {@code SequenceLock} with the default |
254 |
* number of retry attempts to acquire the lock before blocking. |
255 |
*/ |
256 |
public SequenceLock() { sync = new Sync(DEFAULT_SPINS); } |
257 |
|
258 |
/** |
259 |
* Creates an instance of {@code SequenceLock} that will retry |
260 |
* attempts to acquire the lock at least the given number times |
261 |
* before blocking. |
262 |
*/ |
263 |
public SequenceLock(int spins) { sync = new Sync(spins); } |
264 |
|
265 |
/** |
266 |
* Returns the current sequence number of this lock. The sequence |
267 |
* number is advanced upon each acquire or release action. When |
268 |
* this value is odd, the lock is held; when even, it is released. |
269 |
* |
270 |
* @return the current sequence number |
271 |
*/ |
272 |
public long getSequence() { return sync.getSequence(); } |
273 |
|
274 |
/** |
275 |
* Returns the current sequence number when the lock is, or |
276 |
* becomes, available. A lock is available if it is either |
277 |
* released, or is held by the current thread. If the lock is not |
278 |
* available, the current thread becomes disabled for thread |
279 |
* scheduling purposes and lies dormant until the lock has been |
280 |
* released by some other thread. |
281 |
* |
282 |
* @return the current sequence number |
283 |
*/ |
284 |
public long awaitAvailability() { return sync.awaitAvailability(); } |
285 |
|
286 |
/** |
287 |
* Returns the current sequence number if the lock is, or |
288 |
* becomes, available within the specified waiting time. |
289 |
* |
290 |
* <p>If the lock is not available, the current thread becomes |
291 |
* disabled for thread scheduling purposes and lies dormant until |
292 |
* one of three things happens: |
293 |
* |
294 |
* <ul> |
295 |
* |
296 |
* <li>The lock becomes available, in which case the current |
297 |
* sequence number is returned. |
298 |
* |
299 |
* <li>Some other thread {@linkplain Thread#interrupt interrupts} |
300 |
* the current thread, in which case this method throws |
301 |
* {@link InterruptedException}. |
302 |
* |
303 |
* <li>The specified waiting time elapses, in which case |
304 |
* this method throws {@link TimeoutException}. |
305 |
* |
306 |
* </ul> |
307 |
* |
308 |
* @param timeout the time to wait for availability |
309 |
* @param unit the time unit of the timeout argument |
310 |
* @return the current sequence number if the lock is available |
311 |
* upon return from this method |
312 |
* @throws InterruptedException if the current thread is interrupted |
313 |
* @throws TimeoutException if the lock was not available within |
314 |
* the specified waiting time |
315 |
* @throws NullPointerException if the time unit is null |
316 |
*/ |
317 |
public long tryAwaitAvailability(long timeout, TimeUnit unit) |
318 |
throws InterruptedException, TimeoutException { |
319 |
return sync.tryAwaitAvailability(unit.toNanos(timeout)); |
320 |
} |
321 |
|
322 |
/** |
323 |
* Acquires the lock. |
324 |
* |
325 |
* <p>If the current thread already holds this lock then the hold count |
326 |
* is incremented by one and the method returns immediately without |
327 |
* incrementing the sequence number. |
328 |
* |
329 |
* <p>If this lock not held by another thread, this method |
330 |
* increments the sequence number (which thus becomes an odd |
331 |
* number), sets the lock hold count to one, and returns |
332 |
* immediately. |
333 |
* |
334 |
* <p>If the lock is held by another thread then the current |
335 |
* thread may retry acquiring this lock, depending on the {@code |
336 |
* spin} count established in constructor. If the lock is still |
337 |
* not acquired, the current thread becomes disabled for thread |
338 |
* scheduling purposes and lies dormant until enabled by |
339 |
* some other thread releasing the lock. |
340 |
*/ |
341 |
public void lock() { sync.lock(); } |
342 |
|
343 |
/** |
344 |
* Acquires the lock unless the current thread is |
345 |
* {@linkplain Thread#interrupt interrupted}. |
346 |
* |
347 |
* <p>If the current thread already holds this lock then the hold count |
348 |
* is incremented by one and the method returns immediately without |
349 |
* incrementing the sequence number. |
350 |
* |
351 |
* <p>If this lock not held by another thread, this method |
352 |
* increments the sequence number (which thus becomes an odd |
353 |
* number), sets the lock hold count to one, and returns |
354 |
* immediately. |
355 |
* |
356 |
* <p>If the lock is held by another thread then the current |
357 |
* thread may retry acquiring this lock, depending on the {@code |
358 |
* spin} count established in constructor. If the lock is still |
359 |
* not acquired, the current thread becomes disabled for thread |
360 |
* scheduling purposes and lies dormant until one of two things |
361 |
* happens: |
362 |
* |
363 |
* <ul> |
364 |
* |
365 |
* <li>The lock is acquired by the current thread; or |
366 |
* |
367 |
* <li>Some other thread {@linkplain Thread#interrupt interrupts} the |
368 |
* current thread. |
369 |
* |
370 |
* </ul> |
371 |
* |
372 |
* <p>If the lock is acquired by the current thread then the lock hold |
373 |
* count is set to one and the sequence number is incremented. |
374 |
* |
375 |
* <p>If the current thread: |
376 |
* |
377 |
* <ul> |
378 |
* |
379 |
* <li>has its interrupted status set on entry to this method; or |
380 |
* |
381 |
* <li>is {@linkplain Thread#interrupt interrupted} while acquiring |
382 |
* the lock, |
383 |
* |
384 |
* </ul> |
385 |
* |
386 |
* then {@link InterruptedException} is thrown and the current thread's |
387 |
* interrupted status is cleared. |
388 |
* |
389 |
* <p>In this implementation, as this method is an explicit |
390 |
* interruption point, preference is given to responding to the |
391 |
* interrupt over normal or reentrant acquisition of the lock. |
392 |
* |
393 |
* @throws InterruptedException if the current thread is interrupted |
394 |
*/ |
395 |
public void lockInterruptibly() throws InterruptedException { |
396 |
sync.acquireInterruptibly(1L); |
397 |
} |
398 |
|
399 |
/** |
400 |
* Acquires the lock only if it is not held by another thread at the time |
401 |
* of invocation. |
402 |
* |
403 |
* <p>If the current thread already holds this lock then the hold |
404 |
* count is incremented by one and the method returns {@code true} |
405 |
* without incrementing the sequence number. |
406 |
* |
407 |
* <p>If this lock not held by another thread, this method |
408 |
* increments the sequence number (which thus becomes an odd |
409 |
* number), sets the lock hold count to one, and returns {@code |
410 |
* true}. |
411 |
* |
412 |
* <p>If the lock is held by another thread then this method |
413 |
* returns {@code false}. |
414 |
* |
415 |
* @return {@code true} if the lock was free and was acquired by the |
416 |
* current thread, or the lock was already held by the current |
417 |
* thread; and {@code false} otherwise |
418 |
*/ |
419 |
public boolean tryLock() { return sync.tryAcquire(1L); } |
420 |
|
421 |
/** |
422 |
* Acquires the lock if it is not held by another thread within the given |
423 |
* waiting time and the current thread has not been |
424 |
* {@linkplain Thread#interrupt interrupted}. |
425 |
* |
426 |
* <p>If the current thread already holds this lock then the hold count |
427 |
* is incremented by one and the method returns immediately without |
428 |
* incrementing the sequence number. |
429 |
* |
430 |
* <p>If this lock not held by another thread, this method |
431 |
* increments the sequence number (which thus becomes an odd |
432 |
* number), sets the lock hold count to one, and returns |
433 |
* immediately. |
434 |
* |
435 |
* <p>If the lock is held by another thread then the current |
436 |
* thread may retry acquiring this lock, depending on the {@code |
437 |
* spin} count established in constructor. If the lock is still |
438 |
* not acquired, the current thread becomes disabled for thread |
439 |
* scheduling purposes and lies dormant until one of three things |
440 |
* happens: |
441 |
* |
442 |
* <ul> |
443 |
* |
444 |
* <li>The lock is acquired by the current thread; or |
445 |
* |
446 |
* <li>Some other thread {@linkplain Thread#interrupt interrupts} |
447 |
* the current thread; or |
448 |
* |
449 |
* <li>The specified waiting time elapses |
450 |
* |
451 |
* </ul> |
452 |
* |
453 |
* <p>If the lock is acquired then the value {@code true} is returned and |
454 |
* the lock hold count is set to one. |
455 |
* |
456 |
* <p>If the current thread: |
457 |
* |
458 |
* <ul> |
459 |
* |
460 |
* <li>has its interrupted status set on entry to this method; or |
461 |
* |
462 |
* <li>is {@linkplain Thread#interrupt interrupted} while |
463 |
* acquiring the lock, |
464 |
* |
465 |
* </ul> |
466 |
* then {@link InterruptedException} is thrown and the current thread's |
467 |
* interrupted status is cleared. |
468 |
* |
469 |
* <p>If the specified waiting time elapses then the value {@code false} |
470 |
* is returned. If the time is less than or equal to zero, the method |
471 |
* will not wait at all. |
472 |
* |
473 |
* <p>In this implementation, as this method is an explicit |
474 |
* interruption point, preference is given to responding to the |
475 |
* interrupt over normal or reentrant acquisition of the lock, and |
476 |
* over reporting the elapse of the waiting time. |
477 |
* |
478 |
* @param timeout the time to wait for the lock |
479 |
* @param unit the time unit of the timeout argument |
480 |
* @return {@code true} if the lock was free and was acquired by the |
481 |
* current thread, or the lock was already held by the current |
482 |
* thread; and {@code false} if the waiting time elapsed before |
483 |
* the lock could be acquired |
484 |
* @throws InterruptedException if the current thread is interrupted |
485 |
* @throws NullPointerException if the time unit is null |
486 |
* |
487 |
*/ |
488 |
public boolean tryLock(long timeout, TimeUnit unit) |
489 |
throws InterruptedException { |
490 |
return sync.tryAcquireNanos(1L, unit.toNanos(timeout)); |
491 |
} |
492 |
|
493 |
/** |
494 |
* Attempts to release this lock. |
495 |
* |
496 |
* <p>If the current thread is the holder of this lock then the |
497 |
* hold count is decremented. If the hold count is now zero then |
498 |
* the sequence number is incremented (thus becoming an even |
499 |
* number) and the lock is released. If the current thread is not |
500 |
* the holder of this lock then {@link |
501 |
* IllegalMonitorStateException} is thrown. |
502 |
* |
503 |
* @throws IllegalMonitorStateException if the current thread does not |
504 |
* hold this lock |
505 |
*/ |
506 |
public void unlock() { sync.release(1); } |
507 |
|
508 |
/** |
509 |
* Throws UnsupportedOperationException. SequenceLocks |
510 |
* do not support Condition objects. |
511 |
* |
512 |
* @throws UnsupportedOperationException |
513 |
*/ |
514 |
public Condition newCondition() { |
515 |
throw new UnsupportedOperationException(); |
516 |
} |
517 |
|
518 |
/** |
519 |
* Queries the number of holds on this lock by the current thread. |
520 |
* |
521 |
* <p>A thread has a hold on a lock for each lock action that is not |
522 |
* matched by an unlock action. |
523 |
* |
524 |
* <p>The hold count information is typically only used for testing and |
525 |
* debugging purposes. |
526 |
* |
527 |
* @return the number of holds on this lock by the current thread, |
528 |
* or zero if this lock is not held by the current thread |
529 |
*/ |
530 |
public long getHoldCount() { return sync.getHoldCount(); } |
531 |
|
532 |
/** |
533 |
* Queries if this lock is held by the current thread. |
534 |
* |
535 |
* @return {@code true} if current thread holds this lock and |
536 |
* {@code false} otherwise |
537 |
*/ |
538 |
public boolean isHeldByCurrentThread() { return sync.isHeldExclusively(); } |
539 |
|
540 |
/** |
541 |
* Queries if this lock is held by any thread. This method is |
542 |
* designed for use in monitoring of the system state, |
543 |
* not for synchronization control. |
544 |
* |
545 |
* @return {@code true} if any thread holds this lock and |
546 |
* {@code false} otherwise |
547 |
*/ |
548 |
public boolean isLocked() { return sync.isLocked(); } |
549 |
|
550 |
/** |
551 |
* Returns the thread that currently owns this lock, or |
552 |
* {@code null} if not owned. When this method is called by a |
553 |
* thread that is not the owner, the return value reflects a |
554 |
* best-effort approximation of current lock status. For example, |
555 |
* the owner may be momentarily {@code null} even if there are |
556 |
* threads trying to acquire the lock but have not yet done so. |
557 |
* This method is designed to facilitate construction of |
558 |
* subclasses that provide more extensive lock monitoring |
559 |
* facilities. |
560 |
* |
561 |
* @return the owner, or {@code null} if not owned |
562 |
*/ |
563 |
protected Thread getOwner() { return sync.getOwner(); } |
564 |
|
565 |
/** |
566 |
* Queries whether any threads are waiting to acquire this lock. Note that |
567 |
* because cancellations may occur at any time, a {@code true} |
568 |
* return does not guarantee that any other thread will ever |
569 |
* acquire this lock. This method is designed primarily for use in |
570 |
* monitoring of the system state. |
571 |
* |
572 |
* @return {@code true} if there may be other threads waiting to |
573 |
* acquire the lock |
574 |
*/ |
575 |
public final boolean hasQueuedThreads() { |
576 |
return sync.hasQueuedThreads(); |
577 |
} |
578 |
|
579 |
/** |
580 |
* Queries whether the given thread is waiting to acquire this |
581 |
* lock. Note that because cancellations may occur at any time, a |
582 |
* {@code true} return does not guarantee that this thread |
583 |
* will ever acquire this lock. This method is designed primarily for use |
584 |
* in monitoring of the system state. |
585 |
* |
586 |
* @param thread the thread |
587 |
* @return {@code true} if the given thread is queued waiting for this lock |
588 |
* @throws NullPointerException if the thread is null |
589 |
*/ |
590 |
public final boolean hasQueuedThread(Thread thread) { |
591 |
return sync.isQueued(thread); |
592 |
} |
593 |
|
594 |
/** |
595 |
* Returns an estimate of the number of threads waiting to |
596 |
* acquire this lock. The value is only an estimate because the number of |
597 |
* threads may change dynamically while this method traverses |
598 |
* internal data structures. This method is designed for use in |
599 |
* monitoring of the system state, not for synchronization |
600 |
* control. |
601 |
* |
602 |
* @return the estimated number of threads waiting for this lock |
603 |
*/ |
604 |
public final int getQueueLength() { |
605 |
return sync.getQueueLength(); |
606 |
} |
607 |
|
608 |
/** |
609 |
* Returns a collection containing threads that may be waiting to |
610 |
* acquire this lock. Because the actual set of threads may change |
611 |
* dynamically while constructing this result, the returned |
612 |
* collection is only a best-effort estimate. The elements of the |
613 |
* returned collection are in no particular order. This method is |
614 |
* designed to facilitate construction of subclasses that provide |
615 |
* more extensive monitoring facilities. |
616 |
* |
617 |
* @return the collection of threads |
618 |
*/ |
619 |
protected Collection<Thread> getQueuedThreads() { |
620 |
return sync.getQueuedThreads(); |
621 |
} |
622 |
|
623 |
/** |
624 |
* Returns a string identifying this lock, as well as its lock state. |
625 |
* The state, in brackets, includes either the String {@code "Unlocked"} |
626 |
* or the String {@code "Locked by"} followed by the |
627 |
* {@linkplain Thread#getName name} of the owning thread. |
628 |
* |
629 |
* @return a string identifying this lock, as well as its lock state |
630 |
*/ |
631 |
public String toString() { |
632 |
Thread o = sync.getOwner(); |
633 |
return super.toString() + ((o == null) ? |
634 |
"[Unlocked]" : |
635 |
"[Locked by thread " + o.getName() + "]"); |
636 |
} |
637 |
|
638 |
} |