線程池相關
源碼:
package java.util.concurrent;
import java.util.List;
import java.util.Collection;
public interface ExecutorService extends Executor {
//啓動一次順序關閉,執行以前提交的任務,但不接受新任務
void shutdown();
//試圖停止所有正在執行的活動任務,暫停處理正在等待的任務,並返回等待執行的任務列表
List<Runnable> shutdownNow();
//如果此執行程序已關閉,則返回 true
boolean isShutdown();
//如果關閉後所有任務都已完成,則返回 true
boolean isTerminated();
//阻塞當前線程:直到所有任務執行完畢、等待超時或者當前線程中斷,纔會返回
boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException;
//提交一個返回值的任務用於執行,返回一個表示任務的未決結果的 Future
<T> Future<T> submit(Callable<T> task);
//提交一個 Runnable 任務用於執行,並返回一個表示該任務的 Future
Future<?> submit(Runnable task);
//提交一個 Runnable 任務用於執行,並返回一個表示該任務的 Future
<T> Future<T> submit(Runnable task, T result);
//執行給定的任務,當所有任務完成時,返回保持任務狀態和結果的 Future 列表
<T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks) throws InterruptedException;
// 執行給定的任務,當所有任務完成或超時期滿時(無論哪個首先發生),返回保持任務狀態和結果的 Future 列表
<T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks,long timeout, TimeUnit unit) throws InterruptedException;
//執行給定的任務,如果某個任務已成功完成(也就是未拋出異常),則返回其結果
<T> T invokeAny(Collection<? extends Callable<T>> tasks) throws InterruptedException, ExecutionException;
//執行給定的任務,如果在給定的超時期滿前某個任務已成功完成(也就是未拋出異常),則返回其結果
<T> T invokeAny(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException;
}
接口 ExecutorService
父接口:
已知子接口:
已知實現類:
AbstractExecutorService, ScheduledThreadPoolExecutor, ThreadPoolExecutor
Executors
類提供了用於此包中所提供的執行程序服務的工廠方法。
提供兩個方法來關閉 ExecutorService:
shutdown()
方法在終止前允許執行以前提交的任務;無法提交新任務。
shutdownNow()
方法阻止等待任務啓動並試圖停止當前正在執行的任務。沒有任務在等待執行,並且無法提交新任務,執行中的任務將會收到中斷信號。
從父接口,繼承得到的 execute(Runnable command) 方法,只能執行Runnable類型的線程,而且還不能得到返回值。在ExecutorService 中 submit() 通過返回一個可獲取返回值的 Future,不僅支持了執行Runnable類型的線程,也支持了Callable的線程執行。
invokeAny() 和 invokeAll() 是批量執行的最常用形式,它們執行任務 collection,然後等待至少一個,或全部任務完成(可使用 ExecutorCompletionService
類來編寫這些方法的自定義變體)。
例如,AbstractExecutorService中invokeAny(Collection<? extends Callable<T>> tasks):
public <T> T invokeAny(Collection<? extends Callable<T>> tasks)
throws InterruptedException, ExecutionException {
try {
return doInvokeAny(tasks, false, 0);//執行上述的私有方法
} catch (TimeoutException cannotHappen) {
assert false;
return null;
}
}
其中的doInvokeAny方法:
private <T> T doInvokeAny(Collection<? extends Callable<T>> tasks,
boolean timed, long nanos)
throws InterruptedException, ExecutionException, TimeoutException {
if (tasks == null)
throw new NullPointerException();
int ntasks = tasks.size();
if (ntasks == 0)
throw new IllegalArgumentException();
List<Future<T>> futures= new ArrayList<Future<T>>(ntasks);
// ExecutorCompletionService負責執行任務,後面調用用poll返回第一個執行結果
ExecutorCompletionService<T> ecs = new ExecutorCompletionService<T>(this);
// 這裏出於效率的考慮,每次提交一個任務之後,就檢查一下有沒有執行完成的任務
try {
ExecutionException ee = null;
long lastTime = timed ? System.nanoTime() : 0;
Iterator<? extends Callable<T>> it = tasks.iterator();
// 先提交一個任務
futures.add(ecs.submit(it.next()));
--ntasks;
int active = 1;
for (;;) {
// 嘗試獲取有沒有執行結果(這個結果是立刻返回的)
Future<T> f = ecs.poll();
// 沒有執行結果
if (f == null) {
// 如果還有任務沒有被提交執行的,就再提交一個任務
if (ntasks > 0) {
--ntasks;
futures.add(ecs.submit(it.next()));
++active;
}
// 沒有任務在執行了,而且沒有拿到一個成功的結果。
else if (active == 0)
break;
// 如果設置了超時情況
else if (timed) {
// 等待執行結果直到有結果或者超時
f = ecs.poll(nanos, TimeUnit.NANOSECONDS);
if (f == null)
throw new TimeoutException();
// 這裏的更新不可少,因爲這個Future可能是執行失敗的情況,那麼還需要再次等待下一個結果,超時的設置還是需要用到。
long now = System.nanoTime();
nanos -= now - lastTime;
lastTime = now;
}
// 沒有設置超時,並且所有任務都被提交了,則一直等到第一個執行結果出來
else
f = ecs.take();
}
// 有返回結果了,嘗試從future中獲取結果,如果失敗了,那麼需要接着等待下一個執行結果
if (f != null) {
--active;
try {
return f.get();
} catch (ExecutionException eex) {
ee = eex;
} catch (RuntimeException rex) {
ee = new ExecutionException(rex);
}
}
}
// ExecutorCompletionService執行時發生錯誤返回了全是null的future
if (ee == null)
ee = new ExecutionException();
throw ee;
} finally {
// 嘗試取消所有的任務(對於已經完成的任務沒有影響)
for (Future<T> f : futures)
f.cancel(true);
}
}
當所有的任務被提交後,任務執行返回的Future會被依次添加到一個BlockingQueue中,然後找到第一個執行成功任務的方法就是從BlockingQueue取出第一個元素,這個就是doInvokeAny方法用到的ExecutorCompletionService的基本原理。
shutdown
void shutdown()
啓動一次順序關閉,執行以前提交的任務,但不接受新任務。如果已經關閉,則調用沒有其他作用。
拋出:
SecurityException
- 如果安全管理器存在並且關閉,此 ExecutorService 可能操作某些不允許調用者修改的線程(因爲它沒有保持 RuntimePermission
("modifyThread")),或者安全管理器的 checkAccess 方法拒絕訪問。
shutdownNow
List<Runnable> shutdownNow()
試圖停止所有正在執行的活動任務,暫停處理正在等待的任務,並返回等待執行的任務列表。
無法保證能夠停止正在處理的活動執行任務,但是會盡力嘗試。例如,通過 Thread.interrupt()
來取消典型的實現,所以無法響應中斷的任務可能將永遠無法終止。
返回:
從未開始執行的任務的列表
拋出:
SecurityException
- 如果安全管理器存在並且關閉,此 ExecutorService 可能操作某些不允許調用者修改的線程(因爲它沒有保持 RuntimePermission
("modifyThread")),或者安全管理器的 checkAccess 方法拒絕訪問。
isShutdown
boolean isShutdown()
如果此執行程序已關閉,則返回 true。
返回:
如果此執行程序已關閉,則返回 true
isTerminated
boolean isTerminated()
如果關閉後所有任務都已完成,則返回 true。注意,除非首先調用 shutdown 或 shutdownNow,否則 isTerminated 永不爲 true。
返回:
如果關閉後所有任務都已完成,則返回 true
awaitTermination
boolean awaitTermination(long timeout,TimeUnit unit) throws InterruptedException
阻塞當前線程:直到所有任務執行完畢、等待超時或者當前線程中斷,纔會返回。
一般在調用shutdown()方法後調用,用來檢測 timeout 時間後線程池是否關閉。
參數:
timeout
- 最長等待時間
unit
- timeout 參數的時間單位
返回:
如果此執行程序終止,則返回 true;如果終止前超時期滿,則返回 false
拋出:
InterruptedException
- 如果等待時發生中斷
submit
<T> Future<T> submit(Callable<T> task)
提交一個返回值的任務用於執行,返回一個表示任務的未決結果的 Future。該 Future 的 get 方法在成功完成時將會返回該任務的結果。
如果想立即阻塞任務的等待,則可以使用 result = exec.submit(aCallable).get(); 形式的構造。
注:Executors
類包括了一組方法,可以轉換某些其他常見的類似於閉包的對象,例如,將 PrivilegedAction
轉換爲 Callable
形式,這樣就可以提交它們了。
參數:
task
- 要提交的任務
返回:
表示任務等待完成的 Future
拋出:
RejectedExecutionException
- 如果任務無法安排執行
NullPointerException
- 如果該任務爲 null
submit
<T> Future<T> submit(Runnable task, T result)
提交一個 Runnable 任務用於執行,並返回一個表示該任務的 Future。該 Future 的 get 方法在成功完成時將會返回給定的結果。
參數:
task
- 要提交的任務
result
- 返回的結果
返回:
表示任務等待完成的 Future
拋出:
RejectedExecutionException
- 如果任務無法安排執行
NullPointerException
- 如果該任務爲 null
submit
Future<?> submit(Runnable task)
提交一個 Runnable 任務用於執行,並返回一個表示該任務的 Future。該 Future 的 get 方法在 成功 完成時將會返回 null。
參數:
task
- 要提交的任務
返回:
表示任務等待完成的 Future
拋出:
RejectedExecutionException
- 如果任務無法安排執行
NullPointerException
- 如果該任務爲 null
invokeAll
<T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks) throws InterruptedException
執行給定的任務,當所有任務完成時,返回保持任務狀態和結果的 Future 列表。返回列表的所有元素的 Future.isDone()
爲 true。注意,可以正常地或通過拋出異常來終止 已完成 任務。如果正在進行此操作時修改了給定的 collection,則此方法的結果是不確定的。
參數:
tasks
- 任務 collection
返回:
表示任務的 Future 列表,列表順序與給定任務列表的迭代器所生成的順序相同,每個任務都已完成。
拋出:
InterruptedException
- 如果等待時發生中斷,在這種情況下取消尚未完成的任務。
NullPointerException
- 如果任務或其任意元素爲 null
RejectedExecutionException
- 如果所有任務都無法安排執行
invokeAll
<T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks,long timeout,TimeUnit unit) throws InterruptedException
執行給定的任務,當所有任務完成或超時期滿時(無論哪個首先發生),返回保持任務狀態和結果的 Future 列表。返回列表的所有元素的 Future.isDone()
爲 true。一旦返回後,即取消尚未完成的任務。注意,可以正常地或通過拋出異常來終止 已完成 任務。如果此操作正在進行時修改了給定的 collection,則此方法的結果是不確定的。
參數:
tasks
- 任務 collection
timeout
- 最長等待時間
unit
- timeout 參數的時間單位
返回:
表示任務的 Future 列表,列表順序與給定任務列表的迭代器所生成的順序相同。如果操作未超時,則已完成所有任務。如果確實超時了,則某些任務尚未完成。
拋出:
InterruptedException
- 如果等待時發生中斷,在這種情況下取消尚未完成的任務
NullPointerException
- 如果任務或其任意元素或 unit 爲 null
RejectedExecutionException
- 如果所有任務都無法安排執行
invokeAny
<T> T invokeAny(Collection<? extends Callable<T>> tasks) throws InterruptedException,ExecutionException
執行給定的任務,如果某個任務已成功完成(也就是未拋出異常),則返回其結果。一旦正常或異常返回後,則取消尚未完成的任務。如果此操作正在進行時修改了給定的 collection,則此方法的結果是不確定的。
參數:
tasks
- 任務 collection
返回:
某個任務返回的結果
拋出:
InterruptedException
- 如果等待時發生中斷
NullPointerException
- 如果任務或其任意元素爲 null
IllegalArgumentException
- 如果任務爲空
ExecutionException
- 如果沒有任務成功完成
RejectedExecutionException
- 如果任務無法安排執行
invokeAny
<T> T invokeAny(Collection<? extends Callable<T>> tasks,long timeout,TimeUnit unit) throws InterruptedException,ExecutionException,TimeoutException
執行給定的任務,如果在給定的超時期滿前某個任務已成功完成(也就是未拋出異常),則返回其結果。一旦正常或異常返回後,則取消尚未完成的任務。如果此操作正在進行時修改了給定的 collection,則此方法的結果是不確定的。
參數:
tasks
- 任務 collection
timeout
- 最長等待時間
unit
- timeout 參數的時間單位
返回:
某個任務返回的結果
拋出:
InterruptedException
- 如果等待時發生中斷
NullPointerException
- 如果任務或其任意元素或 unit 爲 null
TimeoutException
- 如果在所有任務成功完成之前給定的超時期滿
ExecutionException
- 如果沒有任務成功完成
RejectedExecutionException
- 如果任務無法安排執行
調用實例:
- invokeAny取得第一個方法的返回值,當第一個任務結束後,會調用interrupt方法中斷其它任務。
- invokeAll等線程任務執行完畢後,取得全部任務的結果值。
invokeAll(tasks):
package com.thread;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class InvokeAllTest implements Callable<String> {
int a = 0;
public InvokeAllTest(int a){
this.a=a;
}
@Override
public String call(){
System.out.println("當前值爲:" + a);
return Integer.toString(a);
}
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(3);
List<Callable<String>> list = new ArrayList<>();
for (int i = 0; i < 5; i++) {
list.add(new InvokeAllTest(i));
}
try {
List<Future<String>> futures = executorService.invokeAll(list);
for (Future<String> future : futures) {
System.out.println("返回值:"+future.get());
}
} catch (InterruptedException e) {//invokeAll 可能拋出的異常
e.printStackTrace();
} catch (ExecutionException e) {//future.get() 可能拋出的異常
e.printStackTrace();
}
executorService.shutdown();
}
}
運行結果:
當前值爲:0
當前值爲:2
當前值爲:3
當前值爲:4
當前值爲:1
返回值:0
返回值:1
返回值:2
返回值:3
返回值:4
如果在call方法中拋出異常了,只有在main方法調用了future.get(),main線程才能捕獲到異常:
1.不調用future.get():
package com.thread;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class InvokeAllTest implements Callable<String> {
int a = 0;
public InvokeAllTest(int a) {
this.a = a;
}
@Override
public String call(){
System.out.println("當前值爲:" + a);
if (a == 2) {
throw new RuntimeException();
}
return Integer.toString(a);
}
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(3);
List<Callable<String>> list = new ArrayList<>();
for (int i = 0; i < 5; i++) {
list.add(new InvokeAllTest(i));
}
try {
executorService.invokeAll(list);
} catch (InterruptedException e) {//invokeAll 可能拋出的異常
e.printStackTrace();
}
executorService.shutdown();
}
}
運行結果:
當前值爲:0
當前值爲:1
當前值爲:3
當前值爲:4
當前值爲:2
調用 future.get():
package com.thread;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class InvokeAllTest implements Callable<String> {
int a = 0;
public InvokeAllTest(int a) {
this.a = a;
}
@Override
public String call(){
System.out.println("當前值爲:" + a);
if (a == 2) {
throw new RuntimeException();
}
return Integer.toString(a);
}
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(3);
List<Callable<String>> list = new ArrayList<>();
for (int i = 0; i < 5; i++) {
list.add(new InvokeAllTest(i));
}
try {
List<Future<String>> futures = executorService.invokeAll(list);
for (Future<String> future : futures) {
System.out.println("返回值:" + future.get());
}
} catch (InterruptedException e) {//invokeAll 可能拋出的異常
e.printStackTrace();
} catch (ExecutionException e) {//future.get() 可能拋出的異常
e.printStackTrace();
}
executorService.shutdown();
}
}
運行結果:
當前值爲:0
當前值爲:2
當前值爲:1
當前值爲:4
當前值爲:3
返回值:0
返回值:1
java.util.concurrent.ExecutionException: java.lang.RuntimeException
at java.util.concurrent.FutureTask.report(FutureTask.java:122)
at java.util.concurrent.FutureTask.get(FutureTask.java:192)
at com.thread.InvokeAllTest.main(InvokeAllTest.java:37)
Caused by: java.lang.RuntimeException
at com.thread.InvokeAllTest.call(InvokeAllTest.java:22)
at com.thread.InvokeAllTest.call(InvokeAllTest.java:11)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
invokeAll(tasks,timeout,unit)):若在指定時間內任務沒有執行完畢,則interrupt 中斷線程的執行;需要注意:此時無法獲取到任何異常,只有當在Future對象調用get()方法時,纔會拋出 CancellationException 異常。
將上述例子:
executorService.invokeAll(list);
修改爲:
executorService.invokeAll(list, 15, TimeUnit.SECONDS);
若在call()中有異常拋出,只有在main方法調用了future.get(),main線程才能捕獲到異常。
invokeAny(tasks):
package com.thread;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class InvokeAllTest implements Callable<String> {
int a = 0;
public InvokeAllTest(int a) {
this.a = a;
}
@Override
public String call() {
System.out.println("當前值爲:" + a);
return Integer.toString(a);
}
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(3);
List<Callable<String>> list = new ArrayList<>();
for (int i = 0; i < 5; i++) {
list.add(new InvokeAllTest(i));
}
try {
String value = executorService.invokeAny(list);
System.out.println("最後結果值是======:" + value);
} catch (InterruptedException e) {//invokeAll 可能拋出的異常
e.printStackTrace();
} catch (ExecutionException e) {//future.get() 可能拋出的異常
e.printStackTrace();
}
executorService.shutdown();
}
}
運行結果:
當前值爲:0
當前值爲:2
當前值爲:3
當前值爲:1
最後結果值是======:0
當前值爲:4
invokeAny取得了某一個線程返回的值之後,但是其他線程仍將繼續運行,直到運行結束。
如果任意一個任務在call()拋出了異常,並且異常沒有在call()中被顯示捕獲處理,那麼控制檯將不會打印任何異常信息。
package com.thread;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class InvokeAllTest implements Callable<String> {
int a = 0;
public InvokeAllTest(int a) {
this.a = a;
}
@Override
public String call() throws Exception{
if (a>0) {
throw new Exception("error");
}
System.out.println("當前值爲:" + a);
return Integer.toString(a);
}
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(3);
List<Callable<String>> list = new ArrayList<>();
for (int i = 0; i < 5; i++) {
list.add(new InvokeAllTest(i));
}
try {
String value = executorService.invokeAny(list);
System.out.println("最後結果值是======:" + value);
} catch (InterruptedException e) {//invokeAll 可能拋出的異常
e.printStackTrace();
} catch (ExecutionException e) {//future.get() 可能拋出的異常
e.printStackTrace();
}
executorService.shutdown();
}
}
運行結果:
當前值爲:0
最後結果值是======:0
若所有的任務都發生異常,那麼將返回最後一個異常並且輸出異常信息,最終在ExecutionException中被捕獲:
package com.thread;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class InvokeAllTest implements Callable<String> {
int a = 0;
public InvokeAllTest(int a) {
this.a = a;
}
@Override
public String call() throws Exception{
if (a>-1) {
throw new Exception("error");
}
System.out.println("當前值爲:" + a);
return Integer.toString(a);
}
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(3);
List<Callable<String>> list = new ArrayList<>();
for (int i = 0; i < 5; i++) {
list.add(new InvokeAllTest(i));
}
try {
String value = executorService.invokeAny(list);
System.out.println("最後結果值是======:" + value);
} catch (InterruptedException e) {//invokeAll 可能拋出的異常
e.printStackTrace();
} catch (ExecutionException e) {//future.get() 可能拋出的異常
e.printStackTrace();
}
executorService.shutdown();
}
}
運行結果:
java.util.concurrent.ExecutionException: java.lang.Exception: error
at java.util.concurrent.FutureTask.report(FutureTask.java:122)
at java.util.concurrent.FutureTask.get(FutureTask.java:192)
at java.util.concurrent.AbstractExecutorService.doInvokeAny(AbstractExecutorService.java:193)
at java.util.concurrent.AbstractExecutorService.invokeAny(AbstractExecutorService.java:215)
at com.thread.InvokeAllTest.main(InvokeAllTest.java:33)
Caused by: java.lang.Exception: error
at com.thread.InvokeAllTest.call(InvokeAllTest.java:20)
at com.thread.InvokeAllTest.call(InvokeAllTest.java:10)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
invokeAny(tasks,timeout,unit)):在指定時間內取得第一個先執行完任務的結果值,如果超時,則拋出TimeoutException,並且interrupt線程。
將上述例子:
executorService.invokeAny(list);
修改爲:
executorService.invokeAny(list, 15, TimeUnit.SECONDS);
綜合解讀
Executor接口非常單一,就是執行一個Runnable的命令。
public interface Executor {
void execute(Runnable command);
}
ExecutorService接口擴展了Executor接口,增加狀態控制,執行多個任務返回Future。
關於狀態控制的方法:
// 發出關閉信號,不會等到現有任務執行完成再返回,但是現有任務還是會繼續執行,
// 可以調用awaitTermination等待所有任務執行。不再接受新的任務。
void shutdown();
// 立刻關閉,嘗試取消正在執行的任務(不保證會取消成功),返回未被執行的任務
List<Runnable> shutdownNow();
// 是否發出關閉信號
boolean isShutdown();
// 是否所有任務都執行完畢在shutdown之後,也就是如果不調用shutdownNow或者
// shutdown是不可能返回true
boolean isTerminated();
// 進行等待直到所有任務完成或者超時
boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException;
提交單個任務,立刻返回一個Future存儲任務執行的實時狀態
<T> Future<T> submit(Callable<T> task);
<T> Future<T> submit(Runnable task, T result);
Future<?> submit(Runnable task);
執行多個任務的方法,有兩種方式,一種等到所有任務執行完成才返回:
<T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
throws InterruptedException;
<T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks,
long timeout, TimeUnit unit)
throws InterruptedException;
另外一種是等到有一個任務完成,取消其他未完成的任務,返回執行完成的任務的執行結果:
<T> T invokeAny(Collection<? extends Callable<T>> tasks)
throws InterruptedException, ExecutionException;
<T> T invokeAny(Collection<? extends Callable<T>> tasks,
long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException;
通過上面的代碼可以看出ExecutorService可以執行兩種類型的任務:Runnable和Callable,而Callable用的更加多。兩者區別很簡單,前者不會返回執行結果而後者會返回一個執行結果:
public interface Callable<V> {
V call() throws Exception;
}
接着說說Future,也就是執行任務的返回類型。
Future可以看成是一張發票。比如你送件衣服到洗衣店清洗,他們會開張發票給你,你拿着發票可以去拿回你洗好的衣服或者去洗衣店問衣服是否洗好了等等。
public interface Future<V> {
//取消任務,參數mayInterruptIfRunning爲true時,如果要取消的任務正在執行,
//會把執行這個任務的線程設爲中斷,爲false時,正在執行的任務會被允許執行完成
boolean cancel(boolean mayInterruptIfRunning);
boolean isCancelled();
boolean isDone();
//獲取執行結果,如果任務執行中,會等到任務完成再返回
V get() throws InterruptedException, ExecutionException;
V get(long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException;
}
最後看看ScheduledExecutorService接口,該接口是ExecutorService的子接口,增加了定時執行任務的功能:
public interface ScheduledExecutorService extends ExecutorService {
public ScheduledFuture<?> schedule(Runnable command,
long delay, TimeUnit unit);
public <V> ScheduledFuture<V> schedule(Callable<V> callable,
long delay, TimeUnit unit);
// 等待一定時間然後開始執行一個任務,每隔period參數設置的時間
// 重複一次,(多線程執行)
public ScheduledFuture<?> scheduleAtFixedRate(Runnable command,
long initialDelay,
long period,
TimeUnit unit);
// 等待一定時間然後開始執行一個任務,完成後,等待delay參數設置的時間
// 然後在執行一次任務。(單線程執行)
public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command,
long initialDelay,
long delay,
TimeUnit unit);
}