Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/ruby-on-rails/67.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 使异步查询同步_Java_Multithreading_Concurrency - Fatal编程技术网

Java 使异步查询同步

Java 使异步查询同步,java,multithreading,concurrency,Java,Multithreading,Concurrency,我有一个底层异步无序查询/响应系统,我想使其同步。查询和响应可以通过使用唯一ID标记查询来映射,而唯一ID又将伴随相应的响应 我的同步尝试使用了两个s:一个从ID映射到结果,另一个从相同ID映射到es。执行查询时,代码如下所示: public Result execute(Query query) throws InterruptedException { int id = atomicInteger.incrementAndGet(); CountDownLatch latch

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

我的同步尝试使用了两个s:一个从ID映射到结果,另一个从相同ID映射到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
s(特别是因为从未重用id)。有改进的想法吗?

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

  • putIfAbsent(K键,V值)
  • 更换(K键,V键)
  • 删除(K键,V值)
所以,如果您打算保留它们,您应该更改您的用法,这至少可以保证hashmaps的线程安全

除了为每个请求的查询创建一个新的
执行器
,返回结果本身,以便线程在继续工作之前等待其完成:这样,您将以同步方式完成整个任务。

一个新的尝试灵感来自:

现在我只需要这些
ResultFuture
s中的一个
HashMap

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);
}

我认为带有倒计时闩锁的版本可能是最好的解决方案。“实践中的Java并发”(Brian Goetz)实际上谈到了这一点(我认为他称之为值锁存)。它本质上是一种针对所设置值的一次性同步机制

虽然可以使用wait()-notifyAll()机制实现这样的值锁存,但使用CountDownLatch可以得到更简单的实现


CountDownLatch await()-countDown()方法提供了一个正确的发生之前关系。

因此,请删除使用“latch”的代码,但不应在此函数中定义它。不过,我看不到任何东西会使它异步。实际上是底层系统执行异步查询。我已经将该方法重命名为“executeAsyncWithId”来澄清。嘿,我建议你将自己的答案作为答案发布,并接受它!应删除此答案,并将文本作为更新内容放在原始问题中。@James Black,完全可以提问并回答您自己的问题@hakos至少应该接受他自己的答案:)@Tim Bender-好的,仔细看后,我发现这是一个很好的答案,起初我认为这只是对原始示例的修改,只涉及一个HashMap。
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);
}