ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/jsr166e/SequenceLock.java
Revision: 1.12
Committed: Mon Aug 1 06:21:37 2011 UTC (12 years, 10 months ago) by jsr166
Branch: MAIN
Changes since 1.11: +1 -1 lines
Log Message:
add a comma

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