ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/jsr166e/SequenceLock.java
Revision: 1.3
Committed: Fri Jul 15 15:44:48 2011 UTC (12 years, 10 months ago) by dl
Branch: MAIN
Changes since 1.2: +17 -17 lines
Log Message:
typos

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