java併發編程

java併發編程–Executor框架(一)

摘要:

        原貼地址:http://www.cnblogs.com/MOBIN/p/5436482.html Eexecutor作爲靈活且強大的異步執行框架,其支持多種不同類型的任務執行策略,提供了一種標準的方法將任務的提交過程和執行過程解耦開發,基於生產者-消費者模式,其提交任務的線程相當於生產者,執行任務的線程相當於消費者,並用Runnable來表示任務,Executor的實現還提供了對生命週期的支持,以及統計信息收集,應用程序管理機制和性能監視等機制。
 
1.Exexctor簡介
Executor的UML圖:(常用的幾個接口和子類)

Executor:一個接口,其定義了一個接收Runnable對象的方法executor,其方法簽名爲executor(Runnable command),
 
ExecutorService:是一個比Executor使用更廣泛的子類接口,其提供了生命週期管理的方法,以及可跟蹤一個或多個異步任務執行狀況返回Future的方法
 
AbstractExecutorService:ExecutorService執行方法的默認實現
 
ScheduledExecutorService:一個可定時調度任務的接口
 
ScheduledThreadPoolExecutor:ScheduledExecutorService的實現,一個可定時調度任務的線程池
 
ThreadPoolExecutor:線程池,可以通過調用Executors以下靜態工廠方法來創建線程池並返回一個ExecutorService對象
 
2.ThreadPoolExecutor構造函數的各個參數說明
ThreadPoolExecutor方法簽名:
複製代碼
public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue<Runnable> workQueue,
                          ThreadFactory threadFactory,
                          RejectedExecutionHandler handler) //後兩個參數爲可選參數
複製代碼


參數說明:
corePoolSize:核心線程數,如果運行的線程少於corePoolSize,則創建新線程來執行新任務,即使線程池中的其他線程是空閒的
 
maximumPoolSize:最大線程數,可允許創建的線程數,corePoolSize和maximumPoolSize設置的邊界自動調整池大小:
corePoolSize <運行的線程數< maximumPoolSize:僅當隊列滿時才創建新線程
corePoolSize=運行的線程數= maximumPoolSize:創建固定大小的線程池
 
keepAliveTime:如果線程數多於corePoolSize,則這些多餘的線程的空閒時間超過keepAliveTime時將被終止
 
unit:keepAliveTime參數的時間單位
 
workQueue:保存任務的阻塞隊列,與線程池的大小有關:
  當運行的線程數少於corePoolSize時,在有新任務時直接創建新線程來執行任務而無需再進隊列
  當運行的線程數等於或多於corePoolSize,在有新任務添加時則選加入隊列,不直接創建線程
  當隊列滿時,在有新任務時就創建新線程
 
threadFactory:使用ThreadFactory創建新線程,默認使用defaultThreadFactory創建線程
 
handle:定義處理被拒絕任務的策略,默認使用ThreadPoolExecutor.AbortPolicy,任務被拒絕時將拋出RejectExecutorException
 
3.Executors:提供了一系列靜態工廠方法用於創建各種線程池
   newFixedThreadPool:創建可重用且固定線程數的線程池,如果線程池中的所有線程都處於活動狀態,此時再提交任務就在隊列中等待,直到有可用線程;如果線程池中的某個線程由於異常而結束時,線程池就會再補充一條新線程。
方法簽名:
public static ExecutorService newFixedThreadPool(int nThreads) {
    return new ThreadPoolExecutor(nThreads, nThreads,
                                  0L, TimeUnit.MILLISECONDS,
                                  //使用一個基於FIFO排序的阻塞隊列,在所有corePoolSize線程都忙時新任務將在隊列中等待
                                  new LinkedBlockingQueue<Runnable>());
}




   newSingleThreadExecutor:創建一個單線程的Executor,如果該線程因爲異常而結束就新建一條線程來繼續執行後續的任務
方法簽名:
複製代碼
public static ExecutorService newSingleThreadExecutor() {
   return new FinalizableDelegatedExecutorService
                     //corePoolSize和maximumPoolSize都等於,表示固定線程池大小爲1
                        (new ThreadPoolExecutor(1, 1,
                                                0L, TimeUnit.MILLISECONDS,
                                                new LinkedBlockingQueue<Runnable>()));
}
複製代碼



   newScheduledThreadPool:創建一個可延遲執行或定期執行的線程池
方法簽名:
例1:(使用newScheduledThreadPool來模擬心跳機制)
複製代碼
 1 public class HeartBeat {
 2     public static void main(String[] args) {
 3         ScheduledExecutorService executor = Executors.newScheduledThreadPool(5);
 4         Runnable task = new Runnable() {
 5             public void run() {
 6                 System.out.println("HeartBeat.........................");
 7             }
 8         };
 9         executor.scheduleAtFixedRate(task,5,3, TimeUnit.SECONDS);   //5秒後第一次執行,之後每隔3秒執行一次
10     }
11 }
複製代碼


輸出:
HeartBeat....................... //5秒後第一次輸出
........ //每隔3秒輸出一個




   newCachedThreadPool:創建可緩存的線程池,如果線程池中的線程在60秒未被使用就將被移除,在執行新的任務時,當線程池中有之前創建的可用線程就重      用可用線程,否則就新建一條線程
方法簽名:
public static ExecutorService newCachedThreadPool() {
    return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                  60L, TimeUnit.SECONDS,
                                  //使用同步隊列,將任務直接提交給線程
                                  new SynchronousQueue<Runnable>());
}



 
例2:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class ThreadPoolTest {
    public static void main(String[] args) throws InterruptedException {
     ExecutorService threadPool = Executors.newCachedThreadPool();//線程池裏面的線程數會動態變化,並可在線程線被移除前重用
        for (int i = 1; i <= 3; i ++) {
            final  int task = i;   //10個任務
            //TimeUnit.SECONDS.sleep(1);
            threadPool.execute(new Runnable() {    //接受一個Runnable實例
                public void run() {
                        System.out.println("線程名字: " + Thread.currentThread().getName() +  "  任務名爲: "+task);
                }
            });
        }
    }
}



輸出:(爲每個任務新建一條線程,共創建了3條線程)
線程名字: pool-1-thread-1 任務名爲: 1
線程名字: pool-1-thread-2 任務名爲: 2
線程名字: pool-1-thread-3 任務名爲: 3


去掉第6行的註釋其輸出如下:(始終重複利用一條線程,因爲newCachedThreadPool能重用可用線程)
線程名字: pool-1-thread-1 任務名爲: 1
線程名字: pool-1-thread-1 任務名爲: 2
線程名字: pool-1-thread-1 任務名爲: 3


通過使用Executor可以很輕易的實現各種調優  管理  監視  記錄日誌和錯誤報告等待。
 
4.Executor的生命週期
ExecutorService提供了管理Eecutor生命週期的方法,ExecutorService的生命週期包括了:運行  關閉和終止三種狀態。
 
ExecutorService在初始化創建時處於運行狀態。
shutdown方法等待提交的任務執行完成並不再接受新任務,在完成全部提交的任務後關閉
shutdownNow方法將強制終止所有運行中的任務並不再允許提交新任務
 
可以將一個Runnable(如例2)或Callable(如例3)提交給ExecutorService的submit方法執行,最終返回一上Futire用來獲得任務的執行結果或取消任務
例3:(任務執行完成後並返回執行結果)
1
2
3
4
5
6
7
8
9
10
11
public class CallableAndFuture {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        ExecutorService executor = Executors.newSingleThreadExecutor();
        Future<String> future = executor.submit(new Callable<String>() {   //接受一上callable實例
            public String call() throws Exception {
                return "MOBIN";
            }
        });
        System.out.println("任務的執行結果:"+future.get());
    }
}



輸出:
任務的執行結果:MOBIN



 
ExecutorCompletionService:實現了CompletionService,將執行完成的任務放到阻塞隊列中,通過take或poll方法來獲得執行結果
例4:(啓動10條線程,誰先執行完成就返回誰)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class CompletionServiceTest {
    public static void main(String[] args) throws InterruptedException, ExecutionException {
        ExecutorService executor = Executors.newFixedThreadPool(10);        //創建含10.條線程的線程池
        CompletionService completionService = new ExecutorCompletionService(executor);
        for (int i =1; i <=10; i ++) {
            final  int result = i;
            completionService.submit(new Callable() {
                public Object call() throws Exception {
                    Thread.sleep(new Random().nextInt(5000));   //讓當前線程隨機休眠一段時間
                    return result;
                }
            });
        }
        System.out.println(completionService.take().get());   //獲取執行結果
    }
}



輸出結果可能每次都不同(在1到10之間)
3



 
通過Executor來設計應用程序可以簡化開發過程,提高開發效率,並有助於實現併發,在開發中如果需要創建線程可優先考慮使用Executor
 
  
 
 
 
 
 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章