ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/jsr166e/SequenceLock.java
Revision: 1.6
Committed: Sun Jul 17 12:30:29 2011 UTC (12 years, 10 months ago) by dl
Branch: MAIN
Changes since 1.5: +130 -66 lines
Log Message:
Documentation improvements

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