ExecutorService与Casual Thread Spawner [英] ExecutorService vs Casual Thread Spawner
问题描述
我有一个基本的问题,关于 ExecutorService
如何在Java中运行。
I have a basic question about how ExecutorService
works in Java.
很难看到简单地创建 Threads
之间的区别是并行执行某些任务并将每个任务分配给 ThreadPool
。
It is quite hard to see the difference between simply creating Threads
to perform some tasks in parallel and assigning each tasks to the ThreadPool
.
ExecutorService
看起来也非常简单有效,所以我想知道为什么我们不会一直使用它。
The ExecutorService
also looks very simple and efficient to use, so I was wondering why we don't use it all the time.
这只是一种比其他方式更快地执行其工作的问题吗?
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 :
使用执行程序服务: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接口,你能告诉我两者之间的区别吗?在哪种情况下,应该使用特定的一个而不是另一个?
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 ?
使用执行程序服务:计数器(任务)
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
,我的意思是你知道最大并发线程数,并且你知道它们何时以及如何被创建(所以你的JVM不会在突然出现高峰的情况下爆炸。)
While the question and the sample code do not correlate, I'll try clarifying both.
The advantage of ExecutorService over 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).
作者:Vince Emigh:
ExecutorService
还支持cachedThreadPool
,它没有
max。人们选择使用ExecutorService
的主要原因是
防止创建多个线程的开销(通过使用 worker
threads )。它主要用于许多小任务需要在单独的线程上执行
的情况。另外,不要忘记
singleThreadExecutor
。
By Vince Emigh:
ExecutorService
also supportscachedThreadPool
, which doesn't have a max. The main reason people choose to useExecutorService
is 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 aboutsingleThreadExecutor
.
现在,关于 Runnable
vs Callable
的主题,很容易从你的例子中看到。 Callable
s可以返回一个值占位符( Future
),最终将由实际值填充。 Runnable
s无法返回任何内容。
Now, on the topic of Runnable
vs Callable
, it is easy to see from your examples. Callable
s can return a value place-holder (Future
) that will eventually be populated by an actual value in the future. Runnable
s can not return anything.
作者:Vince Emigh:
Runnable
也不能抛出异常,而Callable
可以。
By Vince Emigh:
Runnable
also cannot throw exceptions, whileCallable
can.
这篇关于ExecutorService与Casual Thread Spawner的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!