假设我有一个完整的任务队列,我需要提交给执行者服务 . 我希望他们一次处理一个 . 我能想到的最简单的方法是:
-
从队列中获取任务
-
将其提交给遗嘱执行人
-
在返回的Future上调用.get并阻塞,直到结果可用
-
从队列中取出另一个任务......
但是,我试图完全避免阻塞 . 如果我有10,000个这样的队列,需要一次处理一个任务,我将耗尽堆栈空间,因为它们中的大多数将保持被阻塞的线程 .
我想要的是提交一个任务并提供一个在任务完成时调用的回调 . 我将使用该回叫通知作为发送下一个任务的标志 . (functionaljava和jetlang显然使用了这种非阻塞算法,但我无法理解他们的代码)
如何使用JDK的java.util.concurrent,而不是编写自己的 Actuator 服务?
(向我提供这些任务的队列本身可能会阻塞,但这是一个需要解决的问题)
11 回答
只是为了补充Matt的答案,这有助于,这是一个更加充实的例子来展示回调的使用 .
输出是:
定义回调接口以接收要在完成通知中传递的任何参数 . 然后在任务结束时调用它 .
您甚至可以为Runnable任务编写一般包装器,并将它们提交给
ExecutorService
. 或者,请参阅下面的Java 8内置机制 .通过CompletableFuture,Java 8包含了一种更复杂的方法来组成流程,其中流程可以异步和有条件地完成 . 这是一个人为但完整的通知示例 .
使用Guava's listenable future API并添加回调 . 参看来自网站:
在Java 8中,您可以使用CompletableFuture . 这里's an example I had in my code where I'm使用它来从我的用户服务中获取用户,将它们映射到我的视图对象,然后更新我的视图或显示错误对话框(这是一个GUI应用程序):
它以异步方式执行 . 我使用两种私有方法:
mapUsersToUserViews
和updateView
.您可以扩展
FutureTask
类,并覆盖done()
方法,然后将FutureTask
对象添加到ExecutorService
,这样_908709_方法将在FutureTask
立即完成时调用 .ThreadPoolExecutor
也有beforeExecute
和afterExecute
钩子方法,您可以覆盖和使用它们 . 以下是ThreadPoolExecutor
的Javadocs中的描述 .使用CountDownLatch .
它来自
java.util.concurrent
,它正是在继续之前等待多个线程完成执行的方式 .为了实现您正在寻找的回调效果,这需要一些额外的额外工作 . 也就是说,在一个使用
CountDownLatch
的单独线程中自己处理它并等待它,然后继续通知你需要通知什么 . 回调没有本机支持,或类似于该效果的任何东西 .EDIT: 现在我进一步理解了你的问题,我认为你走得太远了,不必要的 . 如果你定期SingleThreadExecutor,给它所有的任务,它将本机排队 .
如果要确保不会同时运行任何任务,请使用SingleThreadedExecutor . 任务将按提交的顺序处理 . 您甚至不需要执行任务,只需将它们提交给执行官即可 .
使用
ExecutorService
实现Callback
机制的简单代码输出:
主要说明:
如果要按FIFO顺序依次处理过程任务,请将
newFixedThreadPool(5)
替换为newFixedThreadPool(1)
如果要在分析上一个任务的
callback
结果后处理下一个任务,只需在下面取消注释newFixedThreadPool()
取决于您的使用案例 .
一个 . 将共享的
ExecutorService or ThreadPoolExecutor
传递给Callable任务湾将
Callable
方法转换为Callable/Runnable
任务C . 将回调任务推送到
ExecutorService or ThreadPoolExecutor
这是Pache 's answer using Guava' s
ListenableFuture
的扩展 .特别是,
Futures.transform()
返回ListenableFuture
,因此可用于链接异步调用 .Futures.addCallback()
返回void
,因此无法使用用于链接,但有助于在异步完成时处理成功/失败 .NOTE: 除了链接异步任务外,
Futures.transform()
还允许您在单独的执行程序上安排每个任务(本例中未显示) .您可以使用Callable的实现
CallbackInterface是非常基本的东西
现在主要类看起来像这样