當將一個Callable的對象傳遞給ExecutorService的submit方法,則該call方法自動在一個線程上執行,而且會返回執行結果Future對象。
一樣,將Runnable的對象傳遞給ExecutorService的submit方法,則該run方法自動在一個線程上執行,而且會返回執行結果Future對象,可是在該Future對象上調用get方法,將返回null。
call()方法被自動調用,幹活!!! pool-1-thread-1
call()方法被自動調用,幹活!!! pool-1-thread-3
call()方法被自動調用,幹活!!! pool-1-thread-4
call()方法被自動調用,幹活!!! pool-1-thread-6
call()方法被自動調用,幹活!!! pool-1-thread-2
call()方法被自動調用,幹活!!! pool-1-thread-5
call()方法被自動調用,任務的結果是:0 pool-1-thread-1
call()方法被自動調用,任務的結果是:1 pool-1-thread-2
call()方法被自動調用,幹活!!! pool-1-thread-2
call()方法被自動調用,幹活!!! pool-1-thread-6
call()方法被自動調用,幹活!!! pool-1-thread-4
call()方法被自動調用,任務的結果是:2 pool-1-thread-3
call()方法被自動調用,幹活!!! pool-1-thread-3
call()方法被自動調用,任務的結果是:3 pool-1-thread-4
call()方法被自動調用,任務的結果是:4 pool-1-thread-5
call()方法被自動調用,任務的結果是:5 pool-1-thread-6
call()方法被自動調用,任務的結果是:6 pool-1-thread-2
call()方法被自動調用,任務的結果是:7 pool-1-thread-6
call()方法被自動調用,任務的結果是:8 pool-1-thread-4
call()方法被自動調用,任務的結果是:9 pool-1-thread-3
Process finished with exit code 0
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
由於以前一直是用的execute方法,最近有個狀況須要用到submit方法,因此研究了下。java
三個區別:併發
一、接收的參數不同app
二、submit有返回值,而execute沒有dom
Method submit extends base method Executor.execute by creating and returning a Future that can be used to cancel execution and/or wait for completion. 異步
用到返回值的例子,好比說我有不少個作validation的task,我但願全部的task執行完,而後每一個task告訴我它的執行結果,是成功仍是失敗,若是是失敗,緣由是什麼。而後我就能夠把全部失敗的緣由綜合起來發給調用者。ide
我的以爲cancel execution這個用處不大,不多有須要去取消執行的。工具
而最大的用處應該是第二點。學習
三、submit方便Exception處理測試
There is a difference when looking at exception handling. If your tasks throws an exception and if it was submitted with execute
this exception will go to the uncaught exception handler (when you don't have provided one explicitly, the default one will just print the stack trace to System.err
). If you submitted the task with submit
any thrown exception, checked or not, is then part of the task's return status. For a task that was submitted with submit
and that terminates with an exception, the Future.get
will rethrow this exception, wrapped in an ExecutionException
.
意思就是若是你在你的task裏會拋出checked或者unchecked exception,而你又但願外面的調用者可以感知這些exception並作出及時的處理,那麼就須要用到submit,經過捕獲Future.get拋出的異常。
好比說,我有不少更新各類數據的task,我但願若是其中一個task失敗,其它的task就不須要執行了。那我就須要catch Future.get拋出的異常,而後終止其它task的執行,代碼以下:
51cto上有一篇很是好的文章「Java5併發學習」(http://lavasoft.blog.51cto.com/62575/115112),下面的代碼是基於它之上修改的。
- import java.util.ArrayList;
- import java.util.List;
- import java.util.Random;
- 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 ExecutorServiceTest {
- public static void main(String[] args) {
- ExecutorService executorService = Executors.newCachedThreadPool();
- List<Future<String>> resultList = new ArrayList<Future<String>>();
-
-
- for (int i = 0; i < 10; i++) {
-
- Future<String> future = executorService.submit(new TaskWithResult(i));
-
- resultList.add(future);
- }
- executorService.shutdown();
-
-
- for (Future<String> fs : resultList) {
- try {
- System.out.println(fs.get());
- } catch (InterruptedException e) {
- e.printStackTrace();
- } catch (ExecutionException e) {
- executorService.shutdownNow();
- e.printStackTrace();
- return;
- }
- }
- }
- }
-
- class TaskWithResult implements Callable<String> {
- private int id;
-
- public TaskWithResult(int id) {
- this.id = id;
- }
-
-
- public String call() throws Exception {
- System.out.println("call()方法被自動調用,幹活!!! " + Thread.currentThread().getName());
- if (new Random().nextBoolean())
- throw new TaskException("Meet error in task." + Thread.currentThread().getName());
-
- for (int i = 999999999; i > 0; i--)
- ;
- return "call()方法被自動調用,任務的結果是:" + id + " " + Thread.currentThread().getName();
- }
- }
-
- class TaskException extends Exception {
- public TaskException(String message) {
- super(message);
- }
- }
執行的結果相似於:
- call()方法被自動調用,幹活!!! pool-1-thread-1
- call()方法被自動調用,幹活!!! pool-1-thread-2
- call()方法被自動調用,幹活!!! pool-1-thread-3
- call()方法被自動調用,幹活!!! pool-1-thread-5
- call()方法被自動調用,幹活!!! pool-1-thread-7
- call()方法被自動調用,幹活!!! pool-1-thread-4
- call()方法被自動調用,幹活!!! pool-1-thread-6
- call()方法被自動調用,幹活!!! pool-1-thread-7
- call()方法被自動調用,幹活!!! pool-1-thread-5
- call()方法被自動調用,幹活!!! pool-1-thread-8
- call()方法被自動調用,任務的結果是:0 pool-1-thread-1
- call()方法被自動調用,任務的結果是:1 pool-1-thread-2
- java.util.concurrent.ExecutionException: com.cicc.pts.TaskException: Meet error in task.pool-1-thread-3
- at java.util.concurrent.FutureTask$Sync.innerGet(FutureTask.java:222)
- at java.util.concurrent.FutureTask.get(FutureTask.java:83)
- at com.cicc.pts.ExecutorServiceTest.main(ExecutorServiceTest.java:29)
- Caused by: com.cicc.pts.TaskException: Meet error in task.pool-1-thread-3
- at com.cicc.pts.TaskWithResult.call(ExecutorServiceTest.java:57)
- at com.cicc.pts.TaskWithResult.call(ExecutorServiceTest.java:1)
- at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)
- at java.util.concurrent.FutureTask.run(FutureTask.java:138)
- at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
- at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
- at java.lang.Thread.run(Thread.java:619)
能夠看見一旦某個task出錯,其它的task就中止執行。