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

File Contents

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