Executors.newFixedThreadPool(1)和Executors.newSingleThreadExecutor()的区别

28
我的问题是:使用Executors.newFixedThreadPool(1)有意义吗?在两个线程(主线程+另一个线程)的情况下,使用执行器服务是否有效?直接调用new Runnable() {}创建新线程比使用ExecutorService更好吗?对于这种情况,使用ExecutorService的优缺点是什么?
PS:主线程和另一个线程没有访问任何共享资源。
我已经阅读了使用ExecutorService的优势是什么?每次只允许一个线程!
4个回答

27

使用Executors.newFixedThreadPool(1)有意义吗?

这本质上与Executors.newSingleThreadExecutor()相同,只是后者无法重新配置,如javadoc所示,而前者如果转换为ThreadPoolExecutor则可以重新配置。

在两个线程(主线程+另一个线程)的情况下,使用执行程序服务是否高效?

执行程序服务是一个非常薄的包装器,用于明显地促进线程生命周期管理。如果你唯一需要的就是new Thread(runnable).start();然后继续执行,那就没有实际需要使用ExecutorService。

在大多数实际情况下,通过返回的Future对任务的生命周期进行监视,执行程序将在未捕获异常的情况下根据需要重新创建线程,回收线程的性能优势等,使得执行程序服务成为一个更强大的解决方案,并且成本很小。

底线:我不认为使用执行程序服务与线程相比存在任何缺点。

Executors.newSingleThreadExecutor().execute(command)与new Thread(command).start()之间的区别介绍了这两种选项之间的小差异。


1
谢谢你的回答。你所说的“可重构”具体是什么意思? - TheLostMind
5
((ThreadPoolExecutor) fixedThreadPool).setMaximumPoolSize(10); 这行代码将固定大小线程池的最大线程数设置为10,并且现在它不再是单一的线程池了。 - assylias
1
不会重新配置现有的线程,而是允许多个线程同时运行。 - assylias
1
使用Executors.newSingleThreadExecutor()的一个潜在缺点在这篇博客文章中有所描述:https://www.farside.org.uk/201309/learning_from_bad_code。建议使用Executors.newFixedThreadPool(1) - robinhowlett
@robinhowlett 很有趣 - 尽管只有在您放弃对执行程序的引用而没有调用shutdown时才会出现所描述的问题,这可能是首次出现的错误。如果您将执行程序的引用保留在字段中并正确管理其生命周期,则不会遇到此问题。 - assylias
显示剩余2条评论

2

使用 Executors.newFixedThreadPool(1) 是否有意义?

有意义。如果你想按照任务到达的顺序处理所有提交的任务。

在两个线程(主线程 + 另一个线程)的情况下,使用执行器服务是否有效?直接调用 new Runnable(){} 创建新线程比使用 ExecutorService 更好吗?

我更喜欢使用 ExecutorServiceThreadPoolExecutor,即使只有 1 个线程。

请参考以下 SE 问题,了解 ThreadPoolExecutor 相对于新的 Runnable() 的优势:

ExecutorService vs Casual Thread Spawner

在这种情况下使用 ExecutorService 的优缺点是什么?

请查看相关的 SE 问题,了解 ExexutorService 的使用情况:

Java's Fork/Join vs ExecutorService - when to use which?

关于你在主题行中的查询(来自 grepcode),两者是相同的:

newFixedThreadPool API 将返回 ThreadPoolExecutor 作为 ExecutorService:

public static ExecutorService newFixedThreadPool(int nThreads) {
    return new ThreadPoolExecutor(nThreads, nThreads,
                                  0L, TimeUnit.MILLISECONDS,
                                  new LinkedBlockingQueue<Runnable>());

newSingleThreadExecutor() 返回的是一个ThreadPoolExecutor,作为ExecutorService使用:

public static ExecutorService newSingleThreadExecutor() {
    return new FinalizableDelegatedExecutorService
        (new ThreadPoolExecutor(1, 1,
                                0L, TimeUnit.MILLISECONDS,
                                new LinkedBlockingQueue<Runnable>()));

我同意@assylias的答案关于相似性/差异方面的观点。


2
有时需要使用Executors.newFixedThreadPool(1)来确定队列中的任务数量。
private final ExecutorService executor = Executors.newFixedThreadPool(1);

public int getTaskInQueueCount() {
    ThreadPoolExecutor threadPoolExecutor = (ThreadPoolExecutor) executor;
    return threadPoolExecutor.getQueue().size();
}

0

直接通过调用new Runnable(){}来创建新线程是否比使用ExecutorService更好?

如果你想在线程编译后对返回结果进行计算,你可以使用Callable接口,它只能与ExecutorService一起使用,而不能与new Runnable(){}一起使用。ExecutorService的submit()方法接受Callable对象作为参数,并返回Future对象。你可以使用isDone()方法检查任务是否已完成,还可以使用get()方法获取结果。 在这种情况下,ExecutorService比new Runnable(){}更好。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接