ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/jsr166e/SequenceLock.java
Revision: 1.2
Committed: Fri Jul 15 15:04:14 2011 UTC (12 years, 10 months ago) by dl
Branch: MAIN
Changes since 1.1: +17 -113 lines
Log Message:
Don't support Conditions.

File Contents

# Content
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 * the lock is held. When it is even (i.e., ({@code lock.getSequence()
23 * & 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 * or {link Condition} objects, a SequenceLock can be used in the same
35 * 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 *
40 * <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
125 public final boolean tryAcquire(long acquires) {
126 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
142 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 return ((getState() & 1L) == 0L ||
155 getExclusiveOwnerThread() == Thread.currentThread())?
156 1L : -1L; // must return long
157 }
158
159 public final boolean tryReleaseShared(long unused) {
160 return true;
161 }
162
163 public final Condition newCondition() {
164 throw new UnsupportedOperationException();
165 }
166
167 // Other methods in support of SequenceLock
168
169 final long getSequence() {
170 return getState();
171 }
172
173 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
184 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 return (getState() & 1L) == 0L ? null : getExclusiveOwnerThread();
205 }
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 /**
222 * 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 static final int DEFAULT_SPINS =
228 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 * will retry attempts to lock or await release
240 * 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
265 /**
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 * lock hold count to one.
338 *
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 * Throws UnsupportedOperationException. SequenceLocks
444 * do not support Condition objects.
445 *
446 * @throws UnsupportedOperationException
447 */
448 public Condition newCondition() {
449 throw new UnsupportedOperationException();
450 }
451
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 * debugging purposes.
460 *
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