我花了很多时间来研究这个问题,并且有很多方法可以解决Java问题(我特别关注Java 8解决方案,应该注意)。
好的,所以这是我的(通用)情况 - 请注意这是一个例子,所以不要把时间花在它的工作方式/正在做的事情上:
一些模糊的代码结构:
@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
)。
基本上,在缓存调用完成之前,客户端的连接可能会关闭 - 但我希望它已经完成了:)我不确定规则是否与客户端连接的生命周期内的规则相同。
提前感谢您的任何建议,如果有任何不明确的地方,请告诉我......我试图以一种可以理解的方式来定义它,而不了解我正在尝试做的领域知识(我无法透露)。
答案 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
到队列。
现在,我们在讨论处理来自缓存的异步操作的错误。我不会做任何事情,让缓存客户端返回的未来安然无恙。如果出现问题,可能发生的最糟糕的事情是你必须再次访问数据存储区来检索对象。