CountDownLatch简单应用 -- java并发
? 网络程序(或在其他异步的程序)由于是异步返回结果的,通常需要阻塞线程直到结果返回,这个时候,下面的代码就有用了。
?
?
?
?
?
package org.jilen.cookie.concurrent;import java.util.concurrent.CountDownLatch;import java.util.concurrent.TimeUnit;import java.util.concurrent.TimeoutException;/** * This is a simple <strong>future</strong> implementation which <strong>allow * client to set value manually</strong>. <br/> * All get request are blocked before value is set. <br/> * Yes, the <code> new ArrayBlockingQueue(1);</code> can perform the same task. * But this version is much more lightweight * * @author jilen.zhang@gmail.com * @param <V> */public class WaitForValueFuture<V> { /** * latch used to block before value is set */ private CountDownLatch latch = new CountDownLatch(1); private volatile boolean isValueSet = false; private AtomicBoolean isDone = new AtomicBoolean(false) ; /** * @return whether the value is set already */ public boolean isDone() { return isValueSet; } /** * @return get the value, if value is not set, block until it is set * @throws InterruptedException */ public V get() throws InterruptedException { latch.await(); return value; } /** * get the value within specified time * * @param timeout * @param unit * @return * @throws InterruptedException * @throws TimeoutException */ public V get(long timeout, TimeUnit unit) throws InterruptedException, TimeoutException { latch.await(timeout, unit); return value; } /** * binding value to this future * * @param toBeSet */ public void set(V toBeSet) { if(isDone.compareAndSet(false, true)){ this.value = toBeSet; latch.countDown(); } else { throw new IllegalStateException("value is set already"); } }}??
?
下面是一个silly的使用程序
?
?
package org.jilen.cookie.concurrent;import java.util.Map;import java.util.concurrent.ConcurrentHashMap;import java.util.concurrent.atomic.AtomicInteger;public class WaitForValueFutureTest { public static void main(String... args) { Client sample = new Client(); Object message = sample.getValueFromSomewhere(); System.out.println(message); }}class Client { private static Map<Object, WaitForValueFuture<Object>> resultMap = new ConcurrentHashMap<Object, WaitForValueFuture<Object>>(); private static AtomicInteger idGenerator = new AtomicInteger(0); public Object getValueFromSomewhere() { //generate a request id, thus after receive response, the value can be set to the future in the result with this key Integer requestId = idGenerator.getAndDecrement(); WaitForValueFuture<Object> future = new WaitForValueFuture<Object>(); resultMap.put(requestId, future); sendGetRequest(requestId, "hello"); try { return future.get(); } catch (InterruptedException e) { e.printStackTrace(); } finally { //prevent memory leak resultMap.remove(requestId); } return null; } private void sendGetRequest(Integer requestId, Object message) { System.out.println("peformming get request"); //may be sent request to remote server,just sleep instead try { Thread.sleep(10000); } catch (InterruptedException e) { e.printStackTrace(); } //within an nio application, this method may be invoke while read event happend receiveResponse(requestId, "hello world"); } private void receiveResponse(Integer requestId, Object message) { //fill the result resultMap.get(requestId).set(message); }} 1 楼 jilen 2011-08-10 update 0.1 使用atomic boolean 来保证只set一次。