我有一个对象列表,根据用户交互,某些对象需要异步工作。像这样:
for(TheObject o : this.listOfObjects) {
o.doWork();
}
类TheObject
实现了ExecutorService
(SingleThread!),用于完成工作。 TheObject类型的每个对象都实例化ExecutorService
。我不想做lasagna code。我没有同时拥有足够的对象,以创建一个需要线程池的额外提取层。
我想引用有关CachedThreadPools:
的Java文档未使用60秒的线程终止并且 从缓存中删除。因此,一个闲置足够长时间的池 不会消耗任何资源。
第一个问题: SingleThreadExecutor也是如此吗?线程是否被终止? JavaDoc并没有提及任何有关SingleThreadExecutor的内容。在这个应用程序中它甚至不重要,因为我有一些可以依靠的对象。只是好奇心。
此外,doWork()
TheObject
方法需要调用ExecutorService#.submit()
方法来执行异步工作。是否有可能(我敢打赌)隐含地调用doWork()
方法?这是设计异步方法的可行方法吗?
void doWork() {
if(!isRunningAsync) {
myExecutor.submit(doWork());
} else {
// Do Work...
}
}
答案 0 :(得分:7)
第一个问题:SingleThreadExecutor也是如此吗?线程是否被终止?
查看Executors
的源代码,比较newCachedThreadPool
和newSingleThreadExecutor
的实现:
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
主要区别(此处感兴趣)是60L, TimeUnit.SECONDS
和0L, TimeUnit.MILLISECONDS
。
有效地(but not actually),这些参数将传递给ThreadPoolExecutor.setKeepAliveTime
。看一下该方法的Javadoc:
时间值为零将导致多余的线程在执行任务后立即终止。
其中“多余线程”实际上是指“超过核心池大小的线程”。
ThreadPoolExecutor
。(感谢@GPI指出我之前的解释错误。)
答案 1 :(得分:2)
第一个问题:
终止未使用60秒的线程并从缓存中删除。因此,长时间闲置的池不会占用任何资源。
对于SingleThreadExecutor也是如此吗?
SingleThreadExecutor
的工作方式不同。由于创建期间配置的值,它没有超时概念。
终止SingleThread是可能的。但它保证始终存在一个Thread来处理来自任务队列的任务。
public static ExecutorService newSingleThreadExecutor()
创建一个Executor,它使用一个在无界队列中运行的工作线程。 (但请注意,如果此单个线程由于在关闭之前执行期间的故障而终止,则在需要执行后续任务时将使用新的线程。)
保证任务按顺序执行,并且在任何给定时间不会有多个任务处于活动状态。与其他等效的newFixedThreadPool(1)不同,保证返回的执行程序不可重新配置以使用其他线程。
第二个问题:
此外,TheObject的doWork()方法需要调用ExecutorService#.submit()方法来执行异步工作
for(TheObject o : this.listOfObjects) {
o.doWork();
}
可以更改为
ExecutorService executorService = Executors.newSingleThreadExecutor();
executorService.execute(new Runnable() {
public void run() {
System.out.println("Asynchronous task");
}
});
executorService.shutdown();
使用Callable
或Runnable
界面,并使用doWork
方法或run()
方法添加call()
()代码。任务将同时执行。