java - 等待异步任务的安全有效的方法
问题描述
在系统中,我有一个对象 - 我们称之为TaskProcessor
。它保存任务队列,这些任务由某个线程池(ExecutorService
+ PriorityBlockingQueue
)执行。每个任务的结果以某个唯一标识符保存在数据库中。
知道这个唯一标识符的用户可以检查这个任务的结果。结果可能在数据库中,但任务仍可能在队列中等待执行。在那种情况下,UserThread
应该等到任务完成。
此外,以下假设是有效的:
如果他知道唯一标识符,其他人可以将任务排入队列,
TaskProcessor
并且一些随机数可以访问结果。UserThread
UserThread
并且TaskProcess
在同一个应用程序中。TaskProcessor
包含一个线程池,并且UserThread
只是servlet Thread。UserThread
请求结果时应该阻塞,结果还没有完成。UserThread
应在TaskProcessor
完成按唯一标识符分组的任务(或多个任务)后立即解除阻塞
我的第一次尝试(天真的)是在循环中检查结果并休眠一段时间:
// UserThread
while(!checkResultIsInDatabase(uniqueIdentifier))
sleep(someTime)
但我不喜欢它。首先,我在浪费数据库连接。此外,如果任务在睡眠后立即完成,那么即使结果刚刚出现,用户也会等待。
下一次尝试基于等待/通知:
//UserThread
while (!checkResultIsInDatabase())
taskProcessor.wait()
//TaskProcessor
... some complicated calculations
this.notifyAll()
但我也不喜欢。如果更多UserThreads
使用TaskProcessor
,那么每次完成某些任务时它们都会被不必要地唤醒,而且 - 它们会进行不必要的数据库调用。
最后一次尝试是基于我所说的waitingRoom
:
//UserThread
Object mutex = new Object();
taskProcessor.addToWaitingRoom(uniqueIdentifier, mutex)
while (!checkResultIsInDatabase())
mutex.wait()
//TaskProcessor
... Some complicated calculations
if (uniqueIdentifierExistInWaitingRoom(taskUniqueIdentifier))
getMutexFromWaitingRoom(taskUniqueIdentifier).notify()
但这似乎并不安全。在数据库检查和 之间wait()
,可以完成任务(由于尚未调用,因此notify()
不会生效),这可能会导致死锁。UserThread
wait()
看来,我应该在某个地方同步它。但我担心它不会有效。有没有办法纠正我的任何尝试,使它们安全有效?或者也许还有其他更好的方法来做到这一点?
解决方案
您似乎正在寻找某种未来/承诺抽象。看看CompletableFuture,它从 Java 8 开始可用。
CompletableFuture<Void> future = CompletableFuture.runAsync(db::yourExpensiveOperation, executor);
// best approach: attach some callback to run when the future is complete, and handle any errors
future.thenRun(this::onSuccess)
.exceptionally(ex -> logger.error("err", ex));
// if you really need the current thread to block, waiting for the async result:
future.join(); // blocking! returns the result when complete or throws a CompletionException on error
您还可以从异步操作中返回一个(有意义的)值并将结果传递给回调。要使用此功能,请查看supplyAsync()
、thenAccept()
、thenApply()
等whenComplete()
。
您还可以将多个期货组合成一个甚至更多。
推荐阅读
- javascript - 拖放时通过线动态连接节点
- java - 我收到此错误 HTTP 状态 500 – 内部服务器错误,并且在 'javaee_7.xsd' 中也有 '1' 错误
- python - 如何在等待中获取具有类的所有元素
- sqlalchemy - sqlalchemy 可以将关系表示为列表字典吗?
- python - 我的带有 in 函数的代码不执行任务,但在它之外执行相同的任务?
- php - 如何在 JQuery 中包含 php?
- node.js - Heroku 错误 404,“ENOENT:没有这样的文件或目录,stat '/app/client/build/index.html'”
- angular - 发布后以角度显示第一个登录表单的问题
- c - 如何使用文件中的整数搜索记录?
- php - 如何修复此 PHP 错误尝试访问 wordpress 中 bool 类型值的数组偏移量?