ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/jsr166e/extra/SequenceLock.java
Revision: 1.6
Committed: Sun Jul 21 06:24:09 2013 UTC (10 years, 10 months ago) by jsr166
Branch: MAIN
Changes since 1.5: +3 -1 lines
Log Message:
improve javadoc of SequenceLock(int)

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