ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/jsr166e/SequenceLock.java
Revision: 1.8
Committed: Mon Jul 18 14:44:29 2011 UTC (12 years, 10 months ago) by dl
Branch: MAIN
Changes since 1.7: +23 -28 lines
Log Message:
Minor improvements

File Contents

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