1 |
|
/* |
2 |
|
* Written by Doug Lea with assistance from members of JCP JSR-166 |
3 |
< |
* Expert Group and released to the public domain. Use, modify, and |
4 |
< |
* redistribute this code in any way without acknowledgement. |
3 |
> |
* Expert Group and released to the public domain, as explained at |
4 |
> |
* http://creativecommons.org/licenses/publicdomain |
5 |
|
*/ |
6 |
|
|
7 |
|
package java.util.concurrent; |
8 |
|
import java.util.concurrent.locks.*; |
9 |
+ |
import java.util.concurrent.atomic.*; |
10 |
|
|
11 |
|
/** |
12 |
|
* A synchronization aid that allows one or more threads to wait until |
123 |
|
* @author Doug Lea |
124 |
|
*/ |
125 |
|
public class CountDownLatch { |
126 |
< |
private final ReentrantLock lock = new ReentrantLock(); |
127 |
< |
private final Condition zero = lock.newCondition(); |
128 |
< |
private int count; |
126 |
> |
/** |
127 |
> |
* Synchronization control For CountDownLatch. |
128 |
> |
* Uses AQS state to represent count. |
129 |
> |
*/ |
130 |
> |
private static final class Sync extends AbstractQueuedSynchronizer { |
131 |
> |
Sync(int count) { |
132 |
> |
set(count); |
133 |
> |
} |
134 |
> |
|
135 |
> |
public int acquireSharedState(boolean isQueued, int acquires) { |
136 |
> |
return get() == 0? 1 : -1; |
137 |
> |
} |
138 |
> |
|
139 |
> |
public boolean releaseSharedState(int releases) { |
140 |
> |
// Decrement count; signal when transition to zero |
141 |
> |
int c; |
142 |
> |
while ( (c = get()) > 0 && !compareAndSet(c, c-1)) |
143 |
> |
; |
144 |
> |
return c == 1; |
145 |
> |
} |
146 |
> |
} |
147 |
|
|
148 |
+ |
private final Sync sync; |
149 |
|
/** |
150 |
|
* Constructs a <tt>CountDownLatch</tt> initialized with the given |
151 |
|
* count. |
157 |
|
*/ |
158 |
|
public CountDownLatch(int count) { |
159 |
|
if (count < 0) throw new IllegalArgumentException("count < 0"); |
160 |
< |
this.count = count; |
160 |
> |
this.sync = new Sync(count); |
161 |
|
} |
162 |
|
|
163 |
|
/** |
187 |
|
* while waiting. |
188 |
|
*/ |
189 |
|
public void await() throws InterruptedException { |
190 |
< |
final ReentrantLock lock = this.lock; |
171 |
< |
lock.lock(); |
172 |
< |
try { |
173 |
< |
while (count != 0) |
174 |
< |
zero.await(); |
175 |
< |
} finally { |
176 |
< |
lock.unlock(); |
177 |
< |
} |
190 |
> |
sync.acquireSharedInterruptibly(1); |
191 |
|
} |
192 |
|
|
180 |
– |
|
193 |
|
/** |
194 |
|
* Causes the current thread to wait until the latch has counted down to |
195 |
|
* zero, unless the thread is {@link Thread#interrupt interrupted}, |
233 |
|
*/ |
234 |
|
public boolean await(long timeout, TimeUnit unit) |
235 |
|
throws InterruptedException { |
236 |
< |
long nanos = unit.toNanos(timeout); |
225 |
< |
final ReentrantLock lock = this.lock; |
226 |
< |
lock.lock(); |
227 |
< |
try { |
228 |
< |
for (;;) { |
229 |
< |
if (count == 0) |
230 |
< |
return true; |
231 |
< |
nanos = zero.awaitNanos(nanos); |
232 |
< |
if (nanos <= 0) |
233 |
< |
return false; |
234 |
< |
} |
235 |
< |
} finally { |
236 |
< |
lock.unlock(); |
237 |
< |
} |
236 |
> |
return sync.acquireSharedTimed(1, unit.toNanos(timeout)); |
237 |
|
} |
238 |
|
|
240 |
– |
|
241 |
– |
|
239 |
|
/** |
240 |
|
* Decrements the count of the latch, releasing all waiting threads if |
241 |
|
* the count reaches zero. |
246 |
|
* happens. |
247 |
|
*/ |
248 |
|
public void countDown() { |
249 |
< |
final ReentrantLock lock = this.lock; |
253 |
< |
lock.lock(); |
254 |
< |
try { |
255 |
< |
if (count > 0 && --count == 0) |
256 |
< |
zero.signalAll(); |
257 |
< |
} finally { |
258 |
< |
lock.unlock(); |
259 |
< |
} |
249 |
> |
sync.releaseShared(1); |
250 |
|
} |
251 |
|
|
252 |
|
/** |
255 |
|
* @return the current count. |
256 |
|
*/ |
257 |
|
public long getCount() { |
258 |
< |
final ReentrantLock lock = this.lock; |
269 |
< |
lock.lock(); |
270 |
< |
try { |
271 |
< |
return count; |
272 |
< |
} finally { |
273 |
< |
lock.unlock(); |
274 |
< |
} |
258 |
> |
return sync.get(); |
259 |
|
} |
260 |
|
} |