使异步查询同步

时间:2010-07-31 21:03:50

标签: java multithreading concurrency

我有一个底层的异步无序查询/响应系统,我想让它同步。可以通过使用唯一ID标记查询来映射查询和响应,而唯一ID又将伴随相应的响应。

我尝试使其同步使用两个ConcurrentHashMap:一个从ID映射到结果,另一个从相同的ID映射到CountDownLatch es。执行查询时代码如下:

public Result execute(Query query) throws InterruptedException {
    int id = atomicInteger.incrementAndGet();
    CountDownLatch latch = new CountDownLatch(1);
    latchMap.put(id, latch);
    query.executeAsyncWithId(id); // Probably returns before result is ready
    try {
        latch.await(); // Blocks until result is ready
        return resultMap.remove(id);
    } catch (InterruptedException e) {
        latchMap.remove(id); // We are not waiting anymore
        throw e;
    }
}

处理传入结果的代码:

public void handleResult(Result result) {
    int id = result.getId();
    CountDownLatch latch = latchMap.remove(id);
    if (latch == null) {
        return; // Nobody wants result
    }
    resultMap.put(id, result);
    latch.countDown();
}

从一个线程调用此方法,该线程读取底层系统的所有传入结果(只有一个这样的读取器线程)。

首先,我不确定线程​​安全性,但似乎没有必要为此使用两个HashMap(特别是因为ID永远不会被重用)。有任何改进的想法吗?

3 个答案:

答案 0 :(得分:4)

this answer to a similar question启发的新尝试:

public class ResultFuture {

    private volatile Result result = null;
    private final CountDownLatch latch = new CountDownLatch(1);

    public Result get() throws InterruptedException {
        latch.await();
        return result;
    }

    public void set(Result result) {
        this.result = result;
        latch.countDown();
    }
}

现在我只需要HashMapResultFuture中的一个public Result execute(Query query) throws InterruptedException { int id = atomicInteger.incrementAndGet(); ResultFuture resultFuture = new ResultFuture(); resultFutureMap.put(id, resultFuture); query.executeAsyncWithId(id); // Probably returns before result is ready try { return resultFuture.get(); // Blocks until result is ready } finally { resultFutureMap.remove(id); } } public void handleResult(Result result) { int id = result.getId(); ResultFuture resultFuture = resultFutureMap.get(id); if (resultFuture == null) { return; // Nobody wants result } resultFuture.set(result); }

{{1}}

答案 1 :(得分:0)

ConcurrentHashMap的用法意味着您应该只信任在文档中定义为原子的方法,如:

  • putIfAbsent(K key, V val)
  • replace(K key, V val)
  • remove(K key, V val)

因此,如果您计划保留它们,则应更改使用情况,这至少可以保证您的哈希图的线程安全。

除了帽子之外,只需为请求的每个查询创建一个新的Executor,它返回结果本身,以便线程在继续工作之前等待它完成:这样你就可以完成所有的事情。同步时尚..

答案 2 :(得分:0)

我认为使用CountDownLatch的版本可能是最好的解决方案。 “Java Concurrency in Practice”(Brian Goetz)实际上谈到了这一点(我认为他称之为值锁存器)。它本质上是一个设置值的一次性同步机制。

尽管可以使用wait() - notifyAll()机制实现这样的值锁存器,但使用CountDownLatch可以实现更简单的实现。

CountDownLatch await() - countDown()方法提供了一个合适的先发生关系。