SingleThreadExecutor VS 普通线程

SingleThreadExecutor VS plain thread

除了 Executor 接口相对于普通线程(例如管理)有一些优势之外,在执行以下操作之间是否存在任何真正的内部差异(性能差异大,资源消耗...):

ExecutorService executor = Executors.newSingleThreadExecutor();
executor.submit(runnable);

并且:

Thread thread = new Thread(runnable);
thread.start();

我在这里只问一个线程。

如果只得到一个Runnable执行,那么没有太大区别

使用普通线程可能会更有效一些,因为创建一个 ExecutorService 例如 ThreadPoolExecutor 除了创建一个新线程之外还有一些事情要做。比如创建阻塞队列,创建策略,虽然这些都是隐式完成的。

并且您必须 shutdown 执行此可运行程序后执行程序。否则这个池中的单线程永远不会退出。

它是一个抽象,那些总是出现在"cost":

  • 一些(潜在的)数量 "performance penalty"
  • 减少了 "control" 的数量(这就是重点 - 您不需要处理底层细节,所以,如果您不得不处理,...)

主要区别在于该服务允许您提交 多个 任务,而线程可以 运行 恰好一个 Runnable。另一方面,您必须担心诸如 "shutting down" 服务之类的事情。

一条经验法则:性能方面应该接近 "ignorable" 这里。因此,您更喜欢 "more abstract" 执行程序服务解决方案。因为这允许您将关注点与实际线程分开。更重要的是:如果您选择为该服务使用 不同的 类型的实现……您的其余代码不需要关心它。

长话短说:抽象成本,但在这种情况下,您通常更喜欢 "more abstract" 解决方案。因为最终,这会降低解决方案的复杂性。

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       }

documentation of ThreadPoolExecutor解释了它在什么情况下会带来优势:

Thread pools address two different problems: they usually provide improved performance when executing large numbers of asynchronous tasks, due to reduced per-task invocation overhead, and they provide a means of bounding and managing the resources, including threads, consumed when executing a collection of tasks. Each ThreadPoolExecutor also maintains some basic statistics, such as the number of completed tasks.

如果你只需要偶尔 运行 单线程一次(比如每小时一次),那么就性能而言,使用 ThreadPoolExecutor 可能会更慢,因为你需要实例化整个机器(池+线程),然后将其从内存中丢弃。

但是如果您想经常使用这个单线程(比如每 15 秒一次),那么优点是您只创建池和线程一次,将其保存在内存中, 并一直使用它来节省时间,不时创建一个新线程(这可能非常昂贵,如果你想每 15 秒左右使用一次)。

主要区别在于任务执行策略。

通过创建 Thread 实例或子类化 Thread,您基本上是在执行单个任务。

另一方面,使用 Executors.newSingleThreadExecutor() 允许您提交多个任务。由于这些任务保证不会并发执行,因此您可以利用以下线程限制好处:

  • 访问非线程安全的对象时不需要同步
  • 一个任务的记忆效果保证对下一个任务可见