ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/jsr166e/extra/SequenceLock.java
Revision: 1.7
Committed: Sun Jan 18 20:17:33 2015 UTC (9 years, 4 months ago) by jsr166
Branch: MAIN
CVS Tags: HEAD
Changes since 1.6: +1 -0 lines
Log Message:
exactly one blank line before and after package statements

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