35 |
|
* <p>Except for the lack of support for specified fairness policies, |
36 |
|
* 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}. |
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. |
43 |
|
* <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 {@code |
47 |
< |
* volatile} field values into local variables when the lock is not |
48 |
< |
* held, retrying if the sequence number changed while doing so. |
46 |
> |
* apply. These methods should in general be structured as loops that |
47 |
> |
* await lock availability, then read {@code volatile} fields into |
48 |
> |
* 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 |
|
* 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 |
|
* |
56 |
< |
* <pre> {@code |
56 |
> |
* <pre> {@code |
57 |
|
* class Point { |
58 |
< |
* private volatile double x, y; |
59 |
< |
* private final SequenceLock sl = new SequenceLock(); |
58 |
> |
* private volatile double x, y; |
59 |
> |
* private final SequenceLock sl = new SequenceLock(); |
60 |
|
* |
61 |
< |
* void move(double deltaX, double deltaY) { // an exclusively locked method |
62 |
< |
* sl.lock(); |
63 |
< |
* try { |
64 |
< |
* x += deltaX; |
65 |
< |
* y += deltaY; |
66 |
< |
* } finally { |
67 |
< |
* sl.unlock(); |
68 |
< |
* } |
69 |
< |
* } |
61 |
> |
* // an exclusively locked method |
62 |
> |
* void move(double deltaX, double deltaY) { |
63 |
> |
* sl.lock(); |
64 |
> |
* try { |
65 |
> |
* x += deltaX; |
66 |
> |
* y += deltaY; |
67 |
> |
* } finally { |
68 |
> |
* sl.unlock(); |
69 |
> |
* } |
70 |
> |
* } |
71 |
|
* |
72 |
< |
* double distanceFromOriginV1() { // A read-only method |
73 |
< |
* double currentX, currentY; |
74 |
< |
* long seq; |
75 |
< |
* do { |
76 |
< |
* seq = sl.awaitAvailability(); |
77 |
< |
* currentX = x; |
78 |
< |
* currentY = y; |
79 |
< |
* } while (sl.getSequence() != seq); // retry if sequence changed |
80 |
< |
* return Math.sqrt(currentX * currentX + currentY * currentY); |
81 |
< |
* } |
72 |
> |
* // A read-only method |
73 |
> |
* double distanceFromOriginV1() { |
74 |
> |
* double currentX, currentY; |
75 |
> |
* long seq; |
76 |
> |
* do { |
77 |
> |
* seq = sl.awaitAvailability(); |
78 |
> |
* currentX = x; |
79 |
> |
* currentY = y; |
80 |
> |
* } while (sl.getSequence() != seq); // retry if sequence changed |
81 |
> |
* return Math.sqrt(currentX * currentX + currentY * currentY); |
82 |
> |
* } |
83 |
|
* |
84 |
< |
* double distanceFromOriginV2() { // Uses bounded retries before locking |
85 |
< |
* double currentX, currentY; |
86 |
< |
* long seq; |
87 |
< |
* int retries = RETRIES_BEFORE_LOCKING; // for example 8 |
88 |
< |
* try { |
89 |
< |
* do { |
90 |
< |
* if (--retries < 0) |
91 |
< |
* sl.lock(); |
92 |
< |
* seq = sl.awaitAvailability(); |
93 |
< |
* currentX = x; |
94 |
< |
* currentY = y; |
95 |
< |
* } while (sl.getSequence() != seq); |
96 |
< |
* } finally { |
97 |
< |
* if (retries < 0) |
98 |
< |
* sl.unlock(); |
99 |
< |
* } |
100 |
< |
* return Math.sqrt(currentX * currentX + currentY * currentY); |
101 |
< |
* } |
102 |
< |
*}}</pre> |
84 |
> |
* // Uses bounded retries before locking |
85 |
> |
* double distanceFromOriginV2() { |
86 |
> |
* double currentX, currentY; |
87 |
> |
* long seq; |
88 |
> |
* int retries = RETRIES_BEFORE_LOCKING; // for example 8 |
89 |
> |
* try { |
90 |
> |
* do { |
91 |
> |
* if (--retries < 0) |
92 |
> |
* sl.lock(); |
93 |
> |
* seq = sl.awaitAvailability(); |
94 |
> |
* currentX = x; |
95 |
> |
* currentY = y; |
96 |
> |
* } while (sl.getSequence() != seq); |
97 |
> |
* } finally { |
98 |
> |
* if (retries < 0) |
99 |
> |
* sl.unlock(); |
100 |
> |
* } |
101 |
> |
* return Math.sqrt(currentX * currentX + currentY * currentY); |
102 |
> |
* } |
103 |
> |
* }}</pre> |
104 |
|
* |
105 |
|
* @since 1.8 |
106 |
|
* @author Doug Lea |
306 |
|
* @param timeout the time to wait for availability |
307 |
|
* @param unit the time unit of the timeout argument |
308 |
|
* @return the current sequence number if the lock is available |
309 |
< |
* upon return from this method. |
309 |
> |
* upon return from this method |
310 |
|
* @throws InterruptedException if the current thread is interrupted |
311 |
|
* @throws TimeoutException if the lock was not available within |
312 |
< |
* the specified waiting time. |
312 |
> |
* the specified waiting time |
313 |
|
* @throws NullPointerException if the time unit is null |
314 |
|
*/ |
315 |
|
public long tryAwaitAvailability(long timeout, TimeUnit unit) |