23 |
|
* the lock is held. When it is even (i.e., ({@code lock.getSequence() |
24 |
|
* & 1L) == 0L}), the lock is released. Method {@link |
25 |
|
* #awaitAvailability} can be used to await availability of the lock, |
26 |
< |
* returning its current sequence number. Sequence numbers are of type |
27 |
< |
* {@code long} to ensure that they will not wrap around until |
28 |
< |
* hundreds of years of use under current processor rates. A |
29 |
< |
* SequenceLock can be created with a specified number of |
30 |
< |
* spins. Attempts to lock or await release will retry at least the |
31 |
< |
* given number of times before blocking. If not specified, a default, |
32 |
< |
* possibly platform-specific, value is used. |
26 |
> |
* 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 |
|
* |
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 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: |
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 float 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(float deltaX, float 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 |
< |
* float distanceFromOriginV1() { // A read-only method |
73 |
< |
* float 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 (float)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 |
< |
* float distanceFromOriginV2() { // Uses bounded retries before locking |
85 |
< |
* float 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 (float)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 |
109 |
|
private static final long serialVersionUID = 7373984872572414699L; |
110 |
|
|
111 |
|
static final class Sync extends AbstractQueuedLongSynchronizer { |
112 |
+ |
static final long serialVersionUID = 2540673546047039555L; |
113 |
+ |
|
114 |
|
/** |
115 |
|
* The number of times to spin in lock() and awaitAvailability(). |
116 |
|
*/ |
119 |
|
/** |
120 |
|
* The number of reentrant holds on this lock. Uses a long for |
121 |
|
* compatibility with other AbstractQueuedLongSynchronizer |
122 |
< |
* operations. |
122 |
> |
* operations. Accessed only by lock holder. |
123 |
|
*/ |
124 |
|
long holds; |
125 |
|
|
161 |
|
} |
162 |
|
|
163 |
|
public final long tryAcquireShared(long unused) { |
164 |
< |
return ((getState() & 1L) == 0L || |
165 |
< |
getExclusiveOwnerThread() == Thread.currentThread()) ? |
166 |
< |
1L : -1L; // must return long |
164 |
> |
return (((getState() & 1L) == 0L) ? 1L : |
165 |
> |
(getExclusiveOwnerThread() == Thread.currentThread()) ? 0L: |
166 |
> |
-1L); |
167 |
|
} |
168 |
|
|
169 |
|
public final boolean tryReleaseShared(long unused) { |
170 |
< |
return true; |
170 |
> |
return (getState() & 1L) == 0L; |
171 |
|
} |
172 |
|
|
173 |
|
public final Condition newCondition() { |
193 |
|
|
194 |
|
final long awaitAvailability() { |
195 |
|
long s; |
188 |
– |
int k = spins; |
196 |
|
while (((s = getState()) & 1L) != 0L && |
197 |
|
getExclusiveOwnerThread() != Thread.currentThread()) { |
198 |
< |
if (k > 0) |
199 |
< |
--k; |
193 |
< |
else { |
194 |
< |
acquireShared(1L); |
195 |
< |
releaseShared(1L); |
196 |
< |
} |
198 |
> |
acquireShared(1L); |
199 |
> |
releaseShared(1L); |
200 |
|
} |
201 |
|
return s; |
202 |
|
} |
251 |
|
|
252 |
|
/** |
253 |
|
* Creates an instance of {@code SequenceLock} with the default |
254 |
< |
* number of retry attempts to lock or await release before |
252 |
< |
* blocking. |
254 |
> |
* number of retry attempts to acquire the lock before blocking. |
255 |
|
*/ |
256 |
|
public SequenceLock() { sync = new Sync(DEFAULT_SPINS); } |
257 |
|
|
258 |
|
/** |
259 |
< |
* Creates an instance of {@code SequenceLock} that |
260 |
< |
* will retry attempts to lock or await release |
261 |
< |
* at least the given number times before blocking. |
259 |
> |
* Creates an instance of {@code SequenceLock} that will retry |
260 |
> |
* attempts to acquire the lock at least the given number times |
261 |
> |
* before blocking. |
262 |
|
*/ |
263 |
|
public SequenceLock(int spins) { sync = new Sync(spins); } |
264 |
|
|
308 |
|
* @param timeout the time to wait for availability |
309 |
|
* @param unit the time unit of the timeout argument |
310 |
|
* @return the current sequence number if the lock is available |
311 |
< |
* upon return from this method. |
311 |
> |
* upon return from this method |
312 |
|
* @throws InterruptedException if the current thread is interrupted |
313 |
|
* @throws TimeoutException if the lock was not available within |
314 |
< |
* the specified waiting time. |
314 |
> |
* the specified waiting time |
315 |
|
* @throws NullPointerException if the time unit is null |
316 |
|
*/ |
317 |
|
public long tryAwaitAvailability(long timeout, TimeUnit unit) |
527 |
|
* @return the number of holds on this lock by the current thread, |
528 |
|
* or zero if this lock is not held by the current thread |
529 |
|
*/ |
530 |
< |
public long getHoldCount() { return sync.getHoldCount(); } |
530 |
> |
public long getHoldCount() { return sync.getHoldCount(); } |
531 |
|
|
532 |
|
/** |
533 |
|
* Queries if this lock is held by the current thread. |