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

File Contents

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