1. 程式人生 > >併發程式設計-concurrent指南-執行緒池ExecutorService的使用

併發程式設計-concurrent指南-執行緒池ExecutorService的使用

有幾種不同的方式來將任務委託給 ExecutorService 去執行:

  • execute(Runnable)
  • submit(Runnable)
  • submit(Callable)
  • invokeAny(…)
  • invokeAll(…)

execute(Runnable)

execute(Runnable) 方法要求一個 java.lang.Runnable 物件,然後對它進行非同步執行。以下是使用 ExecutorService 執行一個 Runnable 的示例:

ExecutorService executorService = Executors.newSingleThreadExecutor();  

executorService.execute(
new Runnable() { public void run() { System.out.println("Asynchronous task"); } }); executorService.shutdown();

沒有辦法得知被執行的 Runnable 的執行結果。如果有需要的話你得使用一個 Callable(以下將做介紹)。

 

submit(Runnable)

submit(Runnable) 方法也要求一個 Runnable 實現類,但它返回一個 Future 物件。這個 Future 物件可以用來檢查 Runnable 是否已經執行完畢。

以下是 ExecutorService submit() 示例:

Future future = executorService.submit(new Runnable() {  
    public void run() {  
        System.out.println("Asynchronous task");  
    }  
});  

future.get();  //returns null if the task has finished correctly.  

 

submit(Callable)

submit(Callable) 方法類似於 submit(Runnable) 方法,除了它所要求的引數型別之外。Callable 例項除了它的 call() 方法能夠返回一個結果之外和一個 Runnable 很相像。Runnable.run() 不能夠返回一個結果。
Callable 的結果可以通過 submit(Callable) 方法返回的 Future 物件進行獲取。以下是一個 ExecutorService Callable 示例:

import java.util.concurrent.*;

public class Main {
    public static void main(String[] args) {
        ExecutorService executorService = Executors.newSingleThreadExecutor();

        Future future = executorService.submit(new Runnable() {
            public void run() {
                try {
                    TimeUnit.SECONDS.sleep(4);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("Asynchronous task");
            }
        });
        System.out.println("主方法。。。。");
        try {
            System.out.println(future.get());  //returns null if the task has finished correctly.
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }
}

結果:

主方法。。。。
Asynchronous task
null

future.get()會等待子執行緒結束後,打印出資訊。

submit(Callable)

submit(Callable) 方法類似於 submit(Runnable) 方法,除了它所要求的引數型別之外。Callable 例項除了它的 call() 方法能夠返回一個結果之外和一個 Runnable 很相像。Runnable.run() 不能夠返回一個結果。
Callable 的結果可以通過 submit(Callable) 方法返回的 Future 物件進行獲取。以下是一個 ExecutorService Callable 示例:

import java.util.concurrent.*;

public class Main {
    public static void main(String[] args) {
        ExecutorService executorService = Executors.newSingleThreadExecutor();

        Future future = executorService.submit(new Callable(){
            public Object call() throws Exception {
                TimeUnit.SECONDS.sleep(3);
                System.out.println("Asynchronous Callable");
                return "Callable Result";
            }
        });
        System.out.println("主方法。。。。");
        try {
            System.out.println(future.get());  //returns null if the task has finished correctly.
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }
}

結果:

主方法。。。。
Asynchronous Callable
Callable Result

future.get()會等待子執行緒結束後,打印出資訊


invokeAll()

invokeAll() 方法將呼叫你在集合中傳給 ExecutorService 的所有 Callable 物件。invokeAll() 返回一系列的 Future 物件,通過它們你可以獲取每個 Callable 的執行結果。

記住,一個任務可能會由於一個異常而結束,因此它可能沒有 “成功”。無法通過一個 Future 物件來告知我們是兩種結束中的哪一種。

以下是一個程式碼示例:

import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.*;

public class Main {
    public static void main(String[] args) {
        ExecutorService executorService = Executors.newSingleThreadExecutor();

        Set<Callable<String>> callables = new HashSet<Callable<String>>();

        callables.add(new Callable<String>() {
            public String call() throws Exception {
                System.out.println(Thread.currentThread().getName()+",Task 1");
                return "Task 1";
            }
        });
        callables.add(new Callable<String>() {
            public String call() throws Exception {
                System.out.println(Thread.currentThread().getName()+",Task 2");
                return "Task 2";
            }
        });
        callables.add(new Callable<String>() {
            public String call() throws Exception {
                System.out.println(Thread.currentThread().getName()+",Task 3");
                return "Task 3";
            }
        });
        callables.add(new Callable<String>() {
            public String call() throws Exception {
                System.out.println(Thread.currentThread().getName()+",Task 4");
                return "Task 4";
            }
        });
        callables.add(new Callable<String>() {
            public String call() throws Exception {
                System.out.println(Thread.currentThread().getName()+",Task 5");
                return "Task 5";
            }
        });

        try {
            List<Future<String>> futures  = executorService.invokeAll(callables);
            for(Future<String> future : futures){
                System.out.println("future.get = " + future.get());
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
        executorService.shutdown();
    }
}

 

結果:

pool-1-thread-1,Task 2
pool-1-thread-1,Task 5
pool-1-thread-1,Task 4
pool-1-thread-1,Task 1
pool-1-thread-1,Task 3
future.get = Task 2
future.get = Task 5
future.get = Task 4
future.get = Task 1
future.get = Task 3

 

ExecutorService 關閉

使用完 ExecutorService 之後你應該將其關閉,以使其中的執行緒不再執行。

比如,如果你的應用是通過一個 main() 方法啟動的,之後 main 方法退出了你的應用,如果你的應用有一個活動的 ExexutorService 它將還會保持執行。ExecutorService 裡的活動執行緒阻止了 JVM 的關閉。

要終止 ExecutorService 裡的執行緒你需要呼叫 ExecutorService 的 shutdown() 方法。ExecutorService 並不會立即關閉,但它將不再接受新的任務,而且一旦所有執行緒都完成了當前任務的時候,ExecutorService 將會關閉。在 shutdown() 被呼叫之前所有提交給 ExecutorService 的任務都被執行

如果你想要立即關閉 ExecutorService,你可以呼叫 shutdownNow() 方法。這樣會立即嘗試停止所有執行中的任務,並忽略掉那些已提交但尚未開始處理的任務。無法擔保執行任務的正確執行。可能它們被停止了,也可能已經執行結束。