Java多線程之Executor框架

Executors創建線程池的方法:

  • public static ExecutorService newFixedThreadPool(int nThreads)
    創建固定數目線程的線程池。
  • public static ExecutorService newCachedThreadPool()
    創建一個可緩存的線程池,調用execute 將重用以前構造的線程(如果線程可用)。如果現有線程沒有可用的,則創建一個新線程並添加到池中。終止並從緩存中移除那些已有 60 秒鐘未被使用的線程。
  • public static ExecutorService newSingleThreadExecutor()
    創建一個單線程化的Executor。
  • public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize)
    創建一個支持定時及週期性的任務執行的線程池,多數情況下可用來替代Timer類。
Executor executor = Executors.newFixedThreadPool(10);  
Runnable task = new Runnable() {  
    @Override  
    public void run() {  
        System.out.println("task over");  
    }  
};  
executor.execute(task);  

executor = Executors.newScheduledThreadPool(10);  
ScheduledExecutorService scheduler = (ScheduledExecutorService) executor;  
scheduler.scheduleAtFixedRate(task, 10, 10, TimeUnit.SECONDS);  

ExecutorService與生命週期

ExecutorService擴展了Executor並添加了一些生命週期管理的方法。一個Executor的生命週期有三種狀態,運行 ,關閉 ,終止 。Executor創建時處於運行狀態。當調用ExecutorService.shutdown()後,處於關閉狀態,isShutdown()方法返回true。這時,不應該再想Executor中添加任務,所有已添加的任務執行完畢後,Executor處於終止狀態,isTerminated()返回true。
如果Executor處於關閉狀態,往Executor提交任務會拋出unchecked exception RejectedExecutionException。

ExecutorService executorService = (ExecutorService) executor;  
while (!executorService.isShutdown()) {  
    try {  
        executorService.execute(task);  
    } catch (RejectedExecutionException ignored) {  

    }  
}  
executorService.shutdown();  

使用Callable,Future返回結果

Future代表一個異步執行的操作,通過get()方法可以獲得操作的結果,如果異步操作還沒有完成,則,get()會使當前線程阻塞。FutureTask實現了Future和Runable。Callable代表一個有返回值得操作。

Callable<Integer> func = new Callable<Integer>(){  
    public Integer call() throws Exception {  
        System.out.println("inside callable");  
        Thread.sleep(1000);  
        return new Integer(8);  
    }         
};        
FutureTask<Integer> futureTask  = new FutureTask<Integer>(func);  
Thread newThread = new Thread(futureTask);  
newThread.start();  

try {  
    System.out.println("blocking here");  
    Integer result = futureTask.get();  
    System.out.println(result);  
} catch (InterruptedException ignored) {  
} catch (ExecutionException ignored) {  
}  

ExecutoreService提供了submit()方法,傳遞一個Callable,或Runnable,返回Future。如果Executor後臺線程池還沒有完成Callable的計算,這調用返回Future對象的get()方法,會阻塞直到計算完成。


CompletionService

在剛在的例子中,getResult()方法的實現過程中,迭代了FutureTask的數組,如果任務還沒有完成則當前線程會阻塞,如果我們希望任意字任務完成後就把其結果加到result中,而不用依次等待每個任務完成,可以使CompletionService。生產者submit()執行的任務。使用者take()已完成的任務,並按照完成這些任務的順序處理它們的結果 。也就是調用CompletionService的take方法是,會返回按完成順序放回任務的結果,CompletionService內部維護了一個阻塞隊列BlockingQueue,如果沒有任務完成,take()方法也會阻塞。修改剛纔的例子使用CompletionService:

public class ConcurrentCalculator2 {  

    private ExecutorService exec;  
    private CompletionService<Long> completionService;  


    private int cpuCoreNumber;  

    // 內部類  
    class SumCalculator implements Callable<Long> {  
        ......  
    }  

    public ConcurrentCalculator2() {  
        cpuCoreNumber = Runtime.getRuntime().availableProcessors();  
        exec = Executors.newFixedThreadPool(cpuCoreNumber);  
        completionService = new ExecutorCompletionService<Long>(exec);  


    }  

    public Long sum(final int[] numbers) {  
        // 根據CPU核心個數拆分任務,創建FutureTask並提交到Executor  
        for (int i = 0; i < cpuCoreNumber; i++) {  
            int increment = numbers.length / cpuCoreNumber + 1;  
            int start = increment * i;  
            int end = increment * i + increment;  
            if (end > numbers.length)  
                end = numbers.length;  
            SumCalculator subCalc = new SumCalculator(numbers, start, end);   
            if (!exec.isShutdown()) {  
                completionService.submit(subCalc);  


            }  

        }  
        return getResult();  
    }  

    /** 
     * 迭代每個只任務,獲得部分和,相加返回 
     *  
     * @return 
     */  
    public Long getResult() {  
        Long result = 0l;  
        for (int i = 0; i < cpuCoreNumber; i++) {              
            try {  
                Long subSum = completionService.take().get();  
                result += subSum;             
            } catch (InterruptedException e) {  
                e.printStackTrace();  
            } catch (ExecutionException e) {  
                e.printStackTrace();  
            }  
        }  
        return result;  
    }  

    public void close() {  
        exec.shutdown();  
    }  
}  
發佈了43 篇原創文章 · 獲贊 6 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章