java ExecutorService 与 Casual Thread Spawner

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/26938210/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-02 10:54:49  来源:igfitidea点击:

ExecutorService vs Casual Thread Spawner

javamultithreadingexecutorservice

提问by Phil Moesch

I have a basic question about how ExecutorServiceworks in Java.

我有一个关于ExecutorServiceJava 工作原理的基本问题。

It is quite hard to see the difference between simply creating Threadsto perform some tasks in parallel and assigning each tasks to the ThreadPool.

很难看出简单地创建Threads以并行执行某些任务与将每个任务分配给ThreadPool.

The ExecutorServicealso looks very simple and efficient to use, so I was wondering why we don't use it all the time.

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

Is it just a matter of one way executing its job faster than the other ?

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

Here's two very simple examples to show the difference between the two ways :

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

Using executor service: Hello World (task)

使用执行器服务: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);
    }
}

Using executor service: Hello World (creating executor, submitting)

使用执行器服务: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();
    }
}


the following shows a similar example but extending the Callable interface, could you tell me the difference between the two and in which cases one should use a specific one instead of the other ?

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

Using executor service: Counter (task)

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

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;
    } 
}

Using executor service: (creating, submitting)

使用执行器服务:(创建、提交)

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();
    }
}

采纳答案by kaqqao

While the question and the sample code do not correlate, I'll try clarifying both. The advantage of ExecutorServiceover haphazardly spawning threads is that it behaves predictably and avoids the overhead of thread creation, which is relatively big on the JVM (it needs to reserve memory for each thread, for example). By predictability, at least for the fixedThreadPool, I mean you know the maximum number of concurrent threads, and you know when and how they might get created (so your JVM won't blow up in case of sudden peaks).

虽然问题和示例代码不相关,但我会尝试澄清两者。ExecutorService与随意生成线程相比,它的优势在于它的行为可预测并避免了线程创建的开销,这在 JVM 上相对较大(例如,它需要为每个线程保留内存)。通过可预测性,至少对于fixedThreadPool,我的意思是您知道并发线程的最大数量,并且您知道何时以及如何创建它们(因此您的 JVM 不会在突然出现峰值的情况下崩溃)。

By Vince Emigh:ExecutorServicealso supports cachedThreadPool, which doesn't have a max. The main reason people choose to use ExecutorServiceis to prevent the overhead of creating multiple threads (by using worker threads). It's mostly used in cases where many small tasks need to be executed on a separate thread. Also, don't forget about singleThreadExecutor.

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

Now, on the topic of Runnablevs Callable, it is easy to see from your examples. Callables can return a value place-holder (Future) that will eventually be populated by an actual value in the future. Runnables can not return anything.

现在,关于Runnablevs的主题,Callable从您的示例中很容易看出。Callables 可以返回一个值占位符 ( Future),该值占位符 ( ) 最终将由将来的实际值填充。Runnables 不能返回任何东西。

By Vince Emigh:Runnablealso cannot throw exceptions, while Callablecan.

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

回答by Ravindra babu

ExecutorServiceprovides many advantages compared to plain threads

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

  1. You can create/manage/control life cycle of Threads& optimize thread creation cost overheads
  2. You can control processing of tasks( Work Stealing, ForkJoinPool, invokeAll) etc.
  3. You can schedule tasks in Futuretime
  4. You can monitor the progress and health of threads
  1. 您可以创建/管理/控制线程的生命周期并优化线程创建成本开销
  2. 您可以控制任务的处理(工作窃取、ForkJoinPool、invokeAll)等。
  3. 您可以在未来时间安排任务
  4. 您可以监控线程的进度和健康状况

Even for a single Thread, I prefer to use Executors.newFixedThreadPool(1);

即使对于单个线程,我也更喜欢使用 Executors.newFixedThreadPool(1);

Have a look at related SE questions:

看看相关的 SE 问题:

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

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

What are the advantages of using an ExecutorService?

使用 ExecutorService 有什么好处?