Java多線程學習筆記(二)——Executor,Executors,ExecutorService比較


Executor:是Java線程池的超級接口;提供一個execute(Runnable command)方法;我們一般用它的繼承接口ExecutorService。

Executors:是java.util.concurrent包下的一個類,提供了若干個靜態方法,用於生成不同類型的線程池。Executors一共可以創建下面這四類線程池:

  1. newFixedThreadPool創建一個可緩存線程池,如果線程池長度超過處理需要,可靈活回收空閑線程,若無可回收,則新建線程。
  2. newFixedThreadPool 創建一個定長線程池,可控制線程最大並發數,超出的線程會在隊列中等待。
  3. newScheduledThreadPool 創建一個線程池,它可安排在給定延遲后運行命令或者定期地執行。
  4. newSingleThreadExecutor 創建一個使用單個 worker 線程的 Executor,以無界隊列方式來運行該線程。它只會用唯一的工作線程來執行任務,保證所有任務按照指定順序(FIFO, LIFO, 優先級)執行。

ExecutorService:它是線程池定義的一個接口,繼承Executor。有兩個實現類,分別為ThreadPoolExecutor,ScheduledThreadPoolExecutor。

線程池的繼承樹:

這里寫圖片描述

ExecutorService常用的幾個方法:

  1. execute(Runnable)從父類繼承過來的方法
  2. submit(Runnable)
  3. submit(Callable)
  4. invokeAny(...)
  5. invokeAll(...)
  6. shutdown()

execute方法:方法接收一個Runnable實例,並且異步的執行,請看下面的實例:

public class Demo1 {
    
    public static void main(String[] args) {
        ExecutorService executorService = Executors.newSingleThreadExecutor(); //創建一個單線程
        executorService.execute(new Runnable() { //接收一個Runnable實例
            public void run() {
                System.out.println("Asynchronous task");
            }
        });
        executorService.shutdown();
    }
}

這個方法有個問題,就是沒有辦法獲知task的執行結果。如果我們想獲得task的執行結果,我們可以傳入一個Callable的實例(下面會介紹)。

submit(Runnable)方法:返回一個Future對象,通過返回的Future對象,我們可以檢查提交的任務是否執行完畢。

public class Demo2 {
    
    public static void main(String[] args) throws InterruptedException, ExecutionException {
        ExecutorService executorService = Executors.newSingleThreadExecutor(); //創建一個單線程
        Future future = executorService.submit(new Runnable() { //接收一個Runnable實例
            public void run() {
                System.out.println("Asynchronous task");
            }
        });
        System.out.println(future.get()); //任務執行結束返回null.
        executorService.shutdown();
    }

}

submit(Callable):與submit(Callable)類似,也會返回一個Future對象,但是除此之外,submit(Callable)接收的是一個Callable的實現,Callable接口中的call()方法有一個返回值,可以返回任務的執行結果,而Runnable接口中的run()方法是void的,沒有返回值。

public class Demo1 {
    
    public static void main(String[] args) throws InterruptedException, ExecutionException {
        ExecutorService executorService = Executors.newSingleThreadExecutor(); //創建一個單線程
        Future<Object> future = executorService.submit(new Callable<Object>() { //接收一個Callable實例
            public Object call() {
                System.out.println("Asynchronous task");
                return "Callable Result";
            }
        });
        System.out.println("future.get()="+future.get());
        executorService.shutdown();
    }
}

invokeAny(...):方法接收的是一個Callable的集合,執行這個方法不會返回Future,但是會返回所有Callable任務中其中一個任務的執行結果。這個方法也無法保證返回的是哪個任務的執行結果,反正是其中的某一個。

public class Demo2 {
    public static void main(String[] args) throws InterruptedException, ExecutionException {
        ExecutorService executorService = Executors.newSingleThreadExecutor();
        Set<Callable<String>> callables = new HashSet<Callable<String>>();
        
        callables.add(new Callable<String>(){
            @Override
            public String call() throws Exception {
                // TODO Auto-generated method stub
                return "Result1";
            }
            
        });
        
        callables.add(new Callable<String>(){
            @Override
            public String call() throws Exception {
                // TODO Auto-generated method stub
                return "Result2";
            }
            
        });
        
        callables.add(new Callable<String>(){
            @Override
            public String call() throws Exception {
                // TODO Auto-generated method stub
                return "Result3";
            }
            
        });
        
        String result = executorService.invokeAny(callables);        
        System.out.println(result);
        executorService.shutdown();
    }

}

invokeAll(...):與 invokeAny(...)類似也是接收一個Callable集合,但是前者執行之后會返回一個Future的List,其中對應着每個Callable任務執行后的Future對象。

public class Demo3 {

    public static void main(String[] args) throws InterruptedException, ExecutionException {
        ExecutorService executorService = Executors.newSingleThreadExecutor();
        Set<Callable<String>> callables = new HashSet<Callable<String>>();
        
        callables.add(new Callable<String>(){
            @Override
            public String call() throws Exception {
                // TODO Auto-generated method stub
                return "Result1";
            }
            
        });
        
        callables.add(new Callable<String>(){
            @Override
            public String call() throws Exception {
                // TODO Auto-generated method stub
                return "Result2";
            }
            
        });
        
        callables.add(new Callable<String>(){
            @Override
            public String call() throws Exception {
                // TODO Auto-generated method stub
                return "Result3";
            }
            
        });
        
        List<Future<String>> futures = executorService.invokeAll(callables);    //返回一個Future的List集合    
        for(Future<String> future:futures){
            System.out.println("future.get()="+future.get());
        }
        executorService.shutdown();
    }
}

shutdown():我們使用完成ExecutorService之后應該關閉它,否則它里面的線程會一直處於運行狀態。

舉個例子,如果的應用程序是通過main()方法啟動的,在這個main()退出之后,如果應用程序中的ExecutorService沒有關閉,這個應用將一直運行。之所以會出現這種情況,是因為ExecutorService中運行的線程會阻止JVM關閉。

如果要關閉ExecutorService中執行的線程,我們可以調用ExecutorService.shutdown()方法。在調用shutdown()方法之后,ExecutorService不會立即關閉,但是它不再接收新的任務,直到當前所有線程執行完成才會關閉,所有在shutdown()執行之前提交的任務都會被執行。

如果我們想立即關閉ExecutorService,我們可以調用ExecutorService.shutdownNow()方法。這個動作將跳過所有正在執行的任務和被提交還沒有執行的任務。但是它並不對正在執行的任務做任何保證,有可能它們都會停止,也有可能執行完成。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM