ExecutorService vs休闲线程Spawner

我有一个关于ExecutorService如何在Java中工作的基本问题。

很难看出简单创建Threads并行执行一些任务并将每个任务分配给ThreadPool的区别。

ExecutorService看起来非常简单和高效,所以我想知道为什么我们不会一直使用它。

这只是一种方式比另一种更快地执行其工作的问题?

这里有两个非常简单的例子来展示两种方式之间的区别:

使用执行器服务:Hello World(任务)

static class HelloTask implements Runnable {

String msg;

public HelloTask(String msg) {
this.msg = msg; }
public void run() {
long id = Thread.currentThread().getId();
     System.out.println(msg + " from thread:" + id);
   }
}

使用执行者服务:Hello World(创建执行者,提交)

static class HelloTask {
public static void main(String[] args){

int ntasks = 1000;
ExecutorService exs = Executors.newFixedThreadPool(4);

for (int i=0; i<ntasks; i++) { HelloTask t =
new HelloTask("Hello from task " + i); exs.submit(t);
}
exs.shutdown();}}

下面展示了一个类似的例子,但是扩展了Callable接口,你能告诉我两者之间的区别,在哪些情况下应该使用特定的一个而不是另一个?

使用执行器服务:计数器(任务)

static class HelloTaskRet implements Callable<Long> {

String msg;

public HelloTaskRet(String msg) {
this.msg = msg; }

public Long call() {
long tid = Thread.currentThread().getId(); 
System.out.println(msg + " from thread:" + tid); 
return tid;
    } }

使用执行者服务:(创建,提交)

static class HelloTaskRet {

public static void main(String[] args){
int ntasks = 1000;
ExecutorService exs = Executors.newFixedThreadPool(4);

Future<Long>[] futures = (Future<Long>[]) new Future[ntasks];

for (int i=0; i<ntasks; i++) { HelloTaskRet t =
new HelloTaskRet("Hello from task " + i); futures[i] = exs.submit(t);
}
exs.shutdown();

}}

虽然问题和示例代码不相关,但我会尝试澄清两者。 ExecutorService比随便产生线程的优势在于它的行为可预测并避免线程创建的开销,这在JVM上相对较大(例如,它需要为每个线程保留内存)。 至少对于fixedThreadPool ,至少对于fixedThreadPool ,我的意思是你知道并发线程的最大数量,并且你知道它们何时以及如何创建(所以你的JVM在突发峰值时不会爆炸)。

通过Vince Emigh: ExecutorService也支持cachedThreadPool ,它没有最大值。 人们选择使用ExecutorService主要原因是为了防止创建多个线程的开销(通过使用工作线程)。 它主要用于需要在单独的线程上执行许多小任务的情况。 另外,不要忘记singleThreadExecutor

现在,关于Runnable vs Callable的主题,从您的示例中很容易看到。 Callable s可以返回一个价值占有者( Future ),最终将会由未来的实际值填充。 Runnable s不能返回任何内容。

通过Vince Emigh: Runnable也不能抛出异常,而Callable可以。


与普通线程相比,ExecutorService提供了许多优点

  • 您可以创建/管理/控制线程的生命周期并优化线程创建成本的开销
  • 您可以控制任务的处理(工作窃取,ForkJoinPool,invokeAll)等。
  • 您可以在将来的时间安排任务
  • 您可以监视线程的进度和健康状况
  • 即使对于单个线程,我也更喜欢使用Executors.newFixedThreadPool(1);

    看看相关的SE问题:

    Java的Fork / Join与ExecutorService - 何时使用哪个?

    使用ExecutorService有什么好处?

    链接地址: http://www.djcxy.com/p/16383.html

    上一篇: ExecutorService vs Casual Thread Spawner

    下一篇: The difference between the Runnable and Callable interfaces in Java