ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/jsr166e/SequenceLock.java
Revision: 1.1
Committed: Fri Jul 15 13:14:47 2011 UTC (12 years, 11 months ago) by dl
Branch: MAIN
Log Message:
Initial commit of jdk8 targets

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