jdk1.7.0_79
在上一篇《ThreadPoolExecutor線程池原理及其execute方法》中提到了線程池ThreadPoolExecutor的原理以及它的execute方法。本文解析ThreadPoolExecutor#submit。
對于一個任務的執(zhí)行有時我們不需要它返回結果,但是有我們需要它的返回執(zhí)行結果。對于線程來講,如果不需要它返回結果則實現(xiàn)Runnable,而如果需要執(zhí)行結果的話則可以實現(xiàn)Callable。在線程池同樣execute提供一個不需要返回結果的任務執(zhí)行,而對于需要結果返回的則可調用其submit方法。
回顧ThreadPoolExecutor的繼承關系。
在Executor接口中只定義了execute方法,而submit方法則是在ExecutorService接口中定義的。
1
2
3
4
5
6
7
8
|
//ExecutorService public interface ExecutorService extends Executor { ... <T> Future<T> submit(Callable<T> task); <T> Future<T> submit(Runnable task, T result); <T> Future<T> submit(Runnable task); ... } |
而在其子類AbstractExecutorService實現(xiàn)了submit方法。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
//AbstractExecutorService public abstract class AbstractExecutorService implements ExecutorService { ... public <T> Future<T> submit(Callable<T> task) { if (task == null ) throw new NullPointerException(); RunnableFuture<T> ftask = newTaskFor(task); execute(ftask); return ftask; } public <T> Future<T> submit(Runnable task, T result) { if (task == null ) throw new NullPointerException(); RunnableFuture<T> ftask = newTaskFor(task); execute(ftask); return ftask; } public Future<?> submit(Runnable task) { if (task == null ) throw new NullPointerExeption(); RunnableFuture<Void> ftask = newTaskFor(task, null ); execute(ftask); return ftask; } ... } |
在AbstractExecutorService實現(xiàn)的submit方法實際上是一個模板方法,定義了submit方法的算法骨架,其execute交給了子類。(可以看到在很多源碼中,模板方法模式被大量運用,有關模板方法模式可參考《模板方法模式》)
盡管submit方法能提供線程執(zhí)行的返回值,但只有實現(xiàn)了Callable才會有返回值,而實現(xiàn)Runnable的線程則是沒有返回值的,也就是說在上面的3個方法中,submit(Callable<T> task)能獲取到它的返回值,submit(Runnable task, T result)能通過傳入的載體result間接獲得線程的返回值或者準確來說交給線程處理一下,而最后一個方法submit(Runnable task)則是沒有返回值的,就算獲取它的返回值也是null。
下面給出3個例子,來感受下submit方法。
submit(Callable<T> task)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
package com.threadpoolexecutor; import java.util.concurrent.*; /** * ThreadPoolExecutor#sumit(Callable<T> task) * Created by yulinfeng on 6/17/17. */ public class Sumit1 { public static void main(String[] args) throws ExecutionException, InterruptedException { Callable<String> callable = new Callable<String>() { public String call() throws Exception { System.out.println( "This is ThreadPoolExetor#submit(Callable<T> task) method." ); return "result" ; } }; ExecutorService executor = Executors.newSingleThreadExecutor(); Future<String> future = executor.submit(callable); System.out.println(future.get()); } } |
submit(Runnable task, T result)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
|
package com.threadpoolexecutor; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; /** * ThreadPoolExecutor#submit(Runnable task, T result) * Created by yulinfeng on 6/17/17. */ public class Submit2 { public static void main(String[] args) throws ExecutionException, InterruptedException { ExecutorService executor = Executors.newSingleThreadExecutor(); Data data = new Data(); Future<Data> future = executor.submit( new Task(data), data); System.out.println(future.get().getName()); } } class Data { String name; public String getName() { return name; } public void setName(String name) { this .name = name; } } class Task implements Runnable { Data data; public Task(Data data) { this .data = data; } public void run() { System.out.println( "This is ThreadPoolExetor#submit(Runnable task, T result) method." ); data.setName( "kevin" ); } } |
submit(Runnable task)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
package com.threadpoolexecutor; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; /** * ThreadPoolExecutor#sumit(Runnable runnables) * Created by yulinfeng on 6/17/17. */ public class Submit { public static void main(String[] args) throws ExecutionException, InterruptedException { Runnable runnable = new Runnable() { public void run() { System.out.println( "This is ThreadPoolExetor#submit(Runnable runnable) method." ); } }; ExecutorService executor = Executors.newSingleThreadExecutor(); Future future = executor.submit(runnable); System.out.println(future.get()); } } |
通過上面的實例可以看到在調用submit(Runnable runnable)的時候是不需要其定義類型的,也就是說雖然在ExecutorService中對其定義的是泛型方法,而在AbstractExecutorService中則不是泛型方法,因為它沒有返回值。(有關Object、T、?這三者的區(qū)別,可參考《Java中的Object、T(泛型)、?區(qū)別》)。
從上面的源碼可以看到,這三者方法幾乎是一樣的,關鍵就在于:
1
2
|
RunnableFuture<T> ftask = newTaskFor(task); execute(ftask); |
它是如何將一個任務作為參數(shù)傳遞給了newTaskFor,然后調用execute方法,最后進而返回ftask的呢?
1
2
3
4
5
6
7
|
//AbstractExecutorService#newTaskFor protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) { return new FutureTask<T>(callable); } protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) { return new FutureTask<T>(runnable, value); } |
看來是返回了一個FutureTask實例,F(xiàn)utureTask實現(xiàn)了Future和Runnable接口。Future接口是Java線程Future模式的實現(xiàn),可用用來異步計算,實現(xiàn)Runnable接口表示可以作為一個線程執(zhí)行。FutureTask實現(xiàn)了這兩個接口意味著它代表異步計算的結果,同時可以作為一個線程交給Executor來執(zhí)行。有關FutureTask放到下章來單獨解析。所以本文對于線程池ThreadPoolExecutor線程池的submit方法解析并不完整,必須得了解Java線程的Future模式——《老生常談Java中的Future模式》。
以上這篇簡單談談ThreadPoolExecutor線程池之submit方法就是小編分享給大家的全部內容了,希望能給大家一個參考,也希望大家多多支持服務器之家。