ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/jsr166e/SequenceLock.java
Revision: 1.19
Committed: Fri Oct 12 14:09:30 2012 UTC (11 years, 7 months ago) by dl
Branch: MAIN
CVS Tags: HEAD
Changes since 1.18: +0 -0 lines
State: FILE REMOVED
Log Message:
Introduce StampedLock; move SequenceLock to extras

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