后台任务然后在Java任务完成之前结束连接(8)

时间:2015-02-22 18:59:29

标签: java multithreading concurrency java-8

我花了很多时间来研究这个问题,并且有很多方法可以解决Java问题(我特别关注Java 8解决方案,应该注意)。

好的,所以这是我的(通用)情况 - 请注意这是一个例子,所以不要把时间花在它的工作方式/正在做的事情上:

  • 有人通过API调用请求
  • API从数据存储中检索一些数据
  • 但是,我想在某些缓存系统中缓存此聚合响应
  • 我需要调用缓存API(通过REST)来缓存此响应
  • 我不想等到此调用完成后再将响应返回到原始API调用

一些模糊的代码结构:

@GET
@ // api definitions
public Response myAPIMethod(){
    // get data from datastore
    Object o = getData();

    // submit request to cache data, without blocking
    saveDataToCache();

    // return the response to the Client
    return Response.ok(data).build();
}

在返回saveDataToCache之前,无需等待即可在后台运行data的“最佳”(最佳,最安全,最标准)方法是什么?请注意,此缓存不应经常发生(可能每秒几次)。

我尝试了几种方法,特别是使用CompletableFutures但是当我输入一些日志时,它似乎总是在返回响应之前等待(我没有调用get)。

基本上,在缓存调用完成之前,客户端的连接可能会关闭 - 但我希望它已经完成了:)我不确定规则是否与客户端连接的生命周期内的规则相同。

提前感谢您的任何建议,如果有任何不明确的地方,请告诉我......我试图以一种可以理解的方式来定义它,而不了解我正在尝试做的领域知识(我无法透露)。

2 个答案:

答案 0 :(得分:4)

您可以考虑adding要缓存到BlockingQueue的对象,并从队列中拥有一个单独的线程taking并存储到缓存中。

答案 1 :(得分:2)

根据评论,缓存API已经异步(它实际上返回Future)。我想它会创建并管理一个内部ExecutorService或在启动时收到一个。{1}}。

我的观点是没有必要处理要缓存的对象,而是返回的Future异步行为实际上是由缓存客户端提供的。

一种选择是忽略此客户端返回的Future。这种方法的问题在于,在尝试将对象存储在缓存中时,如果发生错误,您将无法采取纠正措施。事实上,你永远不会知道出了什么问题。

另一个选择是照顾返回的Future。一种方法是使用Queue,如另一个答案中所建议的那样,虽然我使用的是ConcurrentLinkedQueue,因为它是无界的并且您已经提到将对象添加到缓存中会发生同样多的事情每秒两次。一旦缓存客户端返回它就可以offer() Future到队列,然后在另一个线程中,运行无限循环,你可以poll()队列Future并且,如果返回非null值,则在其上调用isDone()。 (如果队列返回null,则表示它为空,因此您可能希望睡眠几毫秒)。

如果isDone()返回true,您可以安全地在将来调用get(),由try/catch块包围,捕获任何ExecutionException并将其处理为你希望。 (您可以在缓存上重试操作,记录发生的事情等)。

如果isDone()返回false,您可以再次offer() Future到队列。

现在,我们在讨论处理来自缓存的异步操作的错误。我不会做任何事情,让缓存客户端返回的未来安然无恙。如果出现问题,可能发生的最糟糕的事情是你必须再次访问数据存储区来检索对象。