1. 程式人生 > >JAVA多執行緒的控制JAVA 5.0--Executor

JAVA多執行緒的控制JAVA 5.0--Executor

JAVA多執行緒的控制JAVA 5.0 2010-09-20 10:48

  在Java 5.0之前啟動一個任務是通過呼叫Thread類的start()方法來實現的,任務的提於交和執行是同時進行的,如果你想對任務的執行進行排程或是控制 同時執行的執行緒數量就需要額外編寫程式碼來完成。5.0裡提供了一個新的任務執行架構使你可以輕鬆地排程和控制任務的執行,並且可以建立一個類似資料庫連線 池的執行緒池來執行任務。這個架構主要有三個介面和其相應的具體類組成。這三個介面是Executor, ExecutorService、ScheduledExecutorService:



Executor 介面: 是用來執行Runnable任務的,它只定義一個方法:

  • execute(Runnable command ):執行Ruannable型別的任務

ExecutorService 介面: ExecutorService繼承了Executor的方法,並提供了執行Callable任務和中止任務執行的服務,其定義的方法主要有:

  • submit(task ):可用來提交Callable或Runnable任務,並返回代表此任務的Future物件
  • invokeAll(collection of tasks ):批處理任務集合,並返回一個代表這些任務的Future物件集合
  • shutdown():在完成已提交的任務後關閉服務,不再接受新任務
  • shutdownNow():停止所有正在執行的任務並關閉服務。
  • isTerminated():測試是否所有任務都執行完畢了。
  • isShutdown():測試是否該ExecutorService已被關閉

ScheduledExecutorService 介面 在ExecutorService的基礎上,ScheduledExecutorService提供了按時間安排執行任務的功能,它提供的方法主要有:

  • schedule(task, initDelay ): 安排所提交的Callable或Runnable任務在initDelay指定的時間後執行。
  • scheduleAtFixedRate():安排所提交的Runnable任務按指定的間隔重複執行
  • scheduleWithFixedDelay():安排所提交的Runnable任務在每次執行完後,等待delay所指定的時間後重復執行。

重要的Executors 類

雖然以上提到的介面有其實現的具體類,但為了方便Java 5.0建議使用Executors的工具類來得到Executor介面的具體物件,需要注意的是Executors是一個類,不是Executor的複數 形式。Executors提供了以下一些static的方法:

  • callable(Runnable task ): 將Runnable的任務轉化成Callable的任務
  • newSingleThreadExecutor: 產生一個ExecutorService物件,這個物件只有一個執行緒可用來執行任務,若任務多於一個,任務將按先後順序執行。
  • newCachedThreadPool(): 產生一個ExecutorService物件,這個物件帶有一個執行緒池,執行緒池的大小會根據需要調整,執行緒執行完任務後返回執行緒池,供執行下一次任務使用。
  • newFixedThreadPool(int poolSize ):產生一個ExecutorService物件,這個物件帶有一個大小為poolSize的執行緒池,若任務數量大於poolSize,任務會被放在一個queue裡順序執行。
  • newSingleThreadScheduledExecutor:產生一個ScheduledExecutorService物件,這個物件的執行緒池大小為1,若任務多於一個,任務將按先後順序執行。
  • newScheduledThreadPool(int poolSize ): 產生一個ScheduledExecutorService物件,這個物件的執行緒池大小為poolSize,若任務數量大於poolSize,任務會在一個queue裡等待執行

舉例說明:

應用Executors來建立Thread pool

有時候您需要建立一堆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()方法。