2014-11-14 73 views
14

我有一個關於ExecutorService如何在Java中工作的基本問題。ExecutorService vs Casual Thread Spawner

很難看出簡單地創建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(); 

}} 
+0

這兩個示例都使用'ExecutorService'而不是創建新的線程,所以我不確定在這種情況下兩個示例之間的比較。你對使用'Runnable'何時使用'Callable'感到困惑嗎? – 2014-11-14 20:52:27

回答

13

雖然問題和示例代碼不相關,我會試着澄清兩者。 ExecutorService比偶然產生線程的優勢在於它的行爲可預測並避免線程創建的開銷,這在JVM上相對較大(例如,它需要爲每個線程保留內存)。根據可預見性,至少對於fixedThreadPool,我的意思是你知道併發線程的最大數量,並且你知道它們何時以及如何創建(所以你的JVM在突發峯值時不會爆炸)。

由Vince Emigh: ExecutorService還支持cachedThreadPool,它不具有 最大。人們選擇使用ExecutorService的主要原因是 防止創建多個線程的開銷(通過使用工作者 線程)。它主要用於許多小任務需要在獨立線程上執行的情況。另外,請不要忘記 singleThreadExecutor

現在,關於RunnableCallable的主題,很容易從您的示例中看到。 Callable s可以返回一個價值佔有者(Future),該價值最終將在未來由實際值填充。 Runnable s不能返回任何東西。

由Vince Emigh: Runnable也不能拋出異常,而Callable即可。

+0

沒問題。您應該將其編輯到您的答案中,以便刪除評論 – 2014-11-15 19:41:19

6

ExecutorService相比普通線程

提供了許多優勢
  1. 您可以創建/管理的線程 &優化線程的創建成本費用
  2. /控制生命週期,您可以將任務的控制處理(偷工,ForkJoinPool,invokeAll)等
  3. 您可以安排任務未來時間
  4. 可以監視線程

即使是單線程的,我更喜歡使用Executors.newFixedThreadPool(1);

看一看相關SE問題的進步和健康:

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

What are the advantages of using an ExecutorService?