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