除了
Executor
接口比普通线程(例如管理)具有一些优势之外,执行之间是否存在任何真正的内部差异(大的性能差异,资源消耗......):
ExecutorService executor = Executors.newSingleThreadExecutor();
executor.submit(runnable);
并且:
Thread thread = new Thread(runnable);
thread.start();
我在这里只询问一个线程。
Executors#newSingleThreadExecutor() 在底层创建 ThreadPoolExecutor 对象,
请参阅此处的代码:http://www.docjar.com/html/api/java/util/concurrent/Executors.java.html
133 public static ExecutorService newSingleThreadExecutor() {
134 return new FinalizableDelegatedExecutorService
135 (new ThreadPoolExecutor(1, 1,
136 0L, TimeUnit.MILLISECONDS,
137 new LinkedBlockingQueue<Runnable>()));
138 }
ThreadPoolExecutor 的文档解释了它在什么情况下具有优势:
线程池解决两个不同的问题: 它们通常提供 提高执行大量异步操作时的性能 任务,由于减少了每个任务的调用开销,并且它们提供了 限制和管理资源的方法,包括线程, 执行任务集合时消耗。每个ThreadPoolExecutor 还维护一些基本统计数据,例如完成的数量 任务。
如果您只需要偶尔运行一次单线程(例如每小时一次),那么就性能而言,使用
ThreadPoolExecutor
可能会更慢,因为您需要实例化整个机器(池+线程) ,然后把它从记忆中扔掉。
但是,如果您想经常使用这个单个线程(例如每 15 秒),那么优点是您只创建一次池和线程,将其保留在内存中,并一直使用它,从而节省创建新线程的时间时不时地使用一次线程(如果你想使用它,比如每 15 秒左右使用一次,这可能会非常昂贵)。
通过创建
Thread
实例或子类化
Thread
,您基本上是在执行单个任务。另一方面,使用
Executors.newSingleThreadExecutor()
可以让您提交多个任务。由于这些任务保证“不会”同时执行,因此您可以利用以下“线程限制”的好处:访问非线程安全的对象时不需要同步 一个任务的记忆效果保证对下一个任务可见
这是一个抽象
,而这些总是要付出“代价”:一些(潜在的)“性能损失” 减少“控制”量(这就是重点 - 你不需要处理低级细节,所以,如果你必须这样做,......)
不同类型的实现......您的其余代码不需要关心这一点。
长话短说:抽象需要成本,但在这种情况下,您通常更喜欢“更抽象”的解决方案。因为最终,这会降低解决方案的复杂性。如果你只执行一个
Runnable
使用普通线程可能会更高效一些,因为创建像
ExecutorService
这样的ThreadPoolExecutor
除了创建新线程之外还有其他事情要做。例如,创建阻塞队列、创建策略,尽管这些事情都是隐式完成的。
在执行此可运行程序后,您必须
shutdown
执行器。否则这个池中的单线程将永远不会退出。