From Gossip@Openhome

Java Gossip: Executors

有時候您需要建立一堆Thread來執行一些小任務,然而頻繁的建立Thread有時會是個開銷,因為Thread的建立必須與作業系統互動,如果能建立一個Thread pool來管理這些小的Thread並加以重複使用,對於系統效能會是個改善的方式。

您可以使用Executors來建立Thread pool,Executors有幾個static方法,列出如下:

方法 說明
newCachedThreadPool 建立可以快取的Thread,每個Thread預設可idle 60秒

newFixedThreadPool

包括固定數量的Thread

newSingleThreadExecutor

只有一個Thread,循序的執行指定給它的每個任務
newScheduledThreadPool 可排程的Thread
newSingleThreadScheduledExecutor 單一可排程的Thread

舉個簡單的實例,下面的程式使用newFixedThreadPool方法建立Thread pool,當中包括五個可以重複使用的Thread,您可以指定Runnable物件給它,程式中會產生十個Runnable物件,由於Thread pool中只有五個可用的Thread,所以後來建立的五個Runnable必須等待有空閒的Thread才會被執行:
  • ExecutorDemo.java
package onlyfun.caterpillar;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ExecutorDemo {
public static void main(String[] args) {
ExecutorService service = Executors.newFixedThreadPool(5);

for(int i = 0; i < 10; i++) {
final int count = i;
service.submit(new Runnable() {
public void run() {
System.out.println(count);
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}

}
});
}

service.shutdown(); // 最後記得關閉Thread pool
}
}

submit()方法也接受實作Callable介面的物件,最後傳回Future物件,可以取得Callable執行過後的傳回結果。

如果想利用Executors進行排程,例如排定某個工作30秒後執行:
        ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor( );
        scheduler.schedule(new Runnable( ) {
                               public void run() {
                                   // 排程工作
                               }
                           },
                           30, TimeUnit.SECONDS);


或排定某個工作5秒後執行,之後每30秒執行一次:
        ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor( );
        final ScheduledFuture future = scheduler.scheduleAtFixedRate(new Runnable( ) {
                               public void run() {
                                   // 排程工作
                                   System.out.println("t");
                               }
                           },
                           0, 5, TimeUnit.SECONDS);
       
        // 排定 60 秒後取消future
        scheduler.schedule(new Runnable( ) {
            public void run( ) {
              future.cancel(false);
            }
          }, 60, TimeUnit.SECONDS);



如上所示,想要取消排程任務,可以呼叫ScheduledFuture的cancel()方法。