ExecutorService中submit和execute的區別
importjava.util.concurrent.ExecutorService;
importjava.util.concurrent.Executors;
/**
* Created by IntelliJ IDEA.
*
* @author leizhimin 2008-11-25 14:28:59
*/
publicclassTestCachedThreadPool {
publicstaticvoidmain(String[] args) {
//ExecutorService executorService = Executors.newCachedThreadPool();
ExecutorService executorService = Executors.newFixedThreadPool(5); //ExecutorService executorService = Executors.newSingleThreadExecutor();
for(inti = 0; i < 5; i++) {
executorService.execute(newTestRunnable());
System.out.println("************* a"+ i +" *************");
}
executorService.shutdown();
}
}
classTestRunnableimplementsRunnable {
publicvoidrun() {
System.out.println(Thread.currentThread().getName() +"執行緒被呼叫了。");
while(true) {
try{
Thread.sleep(5000);
System.out.println(Thread.currentThread().getName());
}catch(InterruptedException e) {
e.printStackTrace();
}
}
}
} 執行結果: ************* a0 *************
************* a1 *************
pool-1-thread-2執行緒被呼叫了。
************* a2 *************
pool-1-thread-3執行緒被呼叫了。
pool-1-thread-1執行緒被呼叫了。
************* a3 *************
************* a4 *************
pool-1-thread-4執行緒被呼叫了。
pool-1-thread-5執行緒被呼叫了。
pool-1-thread-2
pool-1-thread-1
pool-1-thread-3
pool-1-thread-5
pool-1-thread-4
pool-1-thread-2
pool-1-thread-1
pool-1-thread-3
pool-1-thread-5
pool-1-thread-4
...... 五、獲取任務的執行的返回值 在Java5之後,任務分兩類:一類是實現了Runnable介面的類,一類是實現了Callable介面的類。兩者都可以被ExecutorService執行,但是Runnable任務沒有返回值,而Callable任務有返回值。並且Callable的call()方法只能通過ExecutorService的(<T>task)方法來執行,並且返回一個<T><T>,是表示任務等待完成的 Future。 public interfaceCallable<V>
importjava.util.List;
importjava.util.concurrent.*;
/**
* Callable介面測試
*
* @author leizhimin 2008-11-26 9:20:13
*/
publicclassCallableDemo {
publicstaticvoidmain(String[] args) {
ExecutorService executorService = Executors.newCachedThreadPool();
List<Future<String>> resultList =newArrayList<Future<String>>();
//建立10個任務並執行
for(inti = 0; i < 10; i++) {
//使用ExecutorService執行Callable型別的任務,並將結果儲存在future變數中
Future<String> future = executorService.submit(newTaskWithResult(i));
//將任務執行結果儲存到List中
resultList.add(future);
}
//遍歷任務的結果
for(Future<String> fs : resultList) {
try{
System.out.println(fs.get());//列印各個執行緒(任務)執行的結果
}catch(InterruptedException e) {
e.printStackTrace();
}catch(ExecutionException e) {
e.printStackTrace();
}finally{
//啟動一次順序關閉,執行以前提交的任務,但不接受新任務。如果已經關閉,則呼叫沒有其他作用。
executorService.shutdown();
}
}
}
}
classTaskWithResultimplementsCallable<String> {
privateintid;
publicTaskWithResult(intid) {
this.id = id;
}
/**
* 任務的具體過程,一旦任務傳給ExecutorService的submit方法,則該方法自動在一個執行緒上執行。
*
* @return
* @throws Exception
*/
publicString call()throwsException {
System.out.println("call()方法被自動呼叫,幹活!!! "+ Thread.currentThread().getName());
//一個模擬耗時的操作
for(inti = 999999; i > 0; i--) ;
return"call()方法被自動呼叫,任務的結果是:"+ id +""+ Thread.currentThread().getName();
}
} 執行結果: 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()方法被自動呼叫,任務的結果是:0pool-1-thread-1
call()方法被自動呼叫,任務的結果是:1pool-1-thread-2
call()方法被自動呼叫,幹活!!! pool-1-thread-2
call()方法被自動呼叫,幹活!!! pool-1-thread-6
call()方法被自動呼叫,幹活!!! pool-1-thread-4
call()方法被自動呼叫,任務的結果是:2pool-1-thread-3
call()方法被自動呼叫,幹活!!! pool-1-thread-3
call()方法被自動呼叫,任務的結果是:3pool-1-thread-4
call()方法被自動呼叫,任務的結果是:4pool-1-thread-5
call()方法被自動呼叫,任務的結果是:5pool-1-thread-6
call()方法被自動呼叫,任務的結果是:6pool-1-thread-2
call()方法被自動呼叫,任務的結果是:7pool-1-thread-6
call()方法被自動呼叫,任務的結果是:8pool-1-thread-4
call()方法被自動呼叫,任務的結果是:9pool-1-thread-3
Process finished with exit code 0
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
因為之前一直是用的execute方法,最近有個情況需要用到submit方法,所以研究了下。
三個區別:
1、接收的引數不一樣
2、submit有返回值,而execute沒有
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告訴我它的執行結果,是成功還是失敗,如果是失敗,原因是什麼。然後我就可以把所有失敗的原因綜合起來發給呼叫者。
個人覺得cancel execution這個用處不大,很少有需要去取消執行的。
而最大的用處應該是第二點。
3、submit方便Exception處理
There is a difference when looking at exception handling. If your tasks throws an exception and if it was submitted withexecute
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 toSystem.err
). If you submitted the task withsubmit
anythrown exception, checked or not, is then part of the task's return status. For a task that was submitted withsubmit
and that terminates with an exception, theFuture.get
will rethrow this exception, wrapped in anExecutionException
.
意思就是如果你在你的task裡會丟擲checked或者unchecked exception,而你又希望外面的呼叫者能夠感知這些exception並做出及時的處理,那麼就需要用到submit,通過捕獲Future.get丟擲的異常。
比如說,我有很多更新各種資料的task,我希望如果其中一個task失敗,其它的task就不需要執行了。那我就需要catchFuture.get丟擲的異常,然後終止其它task的執行,程式碼如下:
51cto上有一篇非常好的文章“Java5併發學習”(http://lavasoft.blog.51cto.com/62575/115112),下面的程式碼是基於它之上修改的。
[java]view plaincopy- importjava.util.ArrayList;
- importjava.util.List;
- importjava.util.Random;
- importjava.util.concurrent.Callable;
- importjava.util.concurrent.ExecutionException;
- importjava.util.concurrent.ExecutorService;
- importjava.util.concurrent.Executors;
- importjava.util.concurrent.Future;
- publicclassExecutorServiceTest{
- publicstaticvoidmain(String[]args){
- ExecutorServiceexecutorService=Executors.newCachedThreadPool();
- List<Future<String>>resultList=newArrayList<Future<String>>();
- //建立10個任務並執行
- for(inti=0;i<10;i++){
- //使用ExecutorService執行Callable型別的任務,並將結果儲存在future變數中
- Future<String>future=executorService.submit(newTaskWithResult(i));
- //將任務執行結果儲存到List中
- resultList.add(future);
- }
- executorService.shutdown();
- //遍歷任務的結果
- for(Future<String>fs:resultList){
- try{
- System.out.println(fs.get());//列印各個執行緒(任務)執行的結果
- }catch(InterruptedExceptione){
- e.printStackTrace();
- }catch(ExecutionExceptione){
- executorService.shutdownNow();
- e.printStackTrace();
- return;
- }
- }
- }
- }
- classTaskWithResultimplementsCallable<String>{
- privateintid;
- publicTaskWithResult(intid){
- this.id=id;
- }
- /**
- *任務的具體過程,一旦任務傳給ExecutorService的submit方法,則該方法自動在一個執行緒上執行。
- *
- *@return
- *@throwsException
- */
- publicStringcall()throwsException{
- System.out.println("call()方法被自動呼叫,幹活!!!"+Thread.currentThread().getName());
- if(newRandom().nextBoolean())
- thrownewTaskException("Meeterrorintask."+Thread.currentThread().getName());
- //一個模擬耗時的操作
- for(inti=999999999;i>0;i--)
- ;
- return"call()方法被自動呼叫,任務的結果是:"+id+""+Thread.currentThread().getName();
- }
- }
- classTaskExceptionextendsException{
- publicTaskException(Stringmessage){
- super(message);
- }
- }
執行的結果類似於: [java]view plaincopy
- 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()方法被自動呼叫,任務的結果是:0pool-1-thread-1
- call()方法被自動呼叫,任務的結果是:1pool-1-thread-2
- java.util.concurrent.ExecutionException:com.cicc.pts.TaskException:Meeterrorintask.pool-1-thread-3
- atjava.util.concurrent.FutureTask$Sync.innerGet(FutureTask.java:222)
- atjava.util.concurrent.FutureTask.get(FutureTask.java:83)
- atcom.cicc.pts.ExecutorServiceTest.main(ExecutorServiceTest.java:29)
- Causedby:com.cicc.pts.TaskException:Meeterrorintask.pool-1-thread-3
- atcom.cicc.pts.TaskWithResult.call(ExecutorServiceTest.java:57)
- atcom.cicc.pts.TaskWithResult.call(ExecutorServiceTest.java:1)
- atjava.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)
- atjava.util.concurrent.FutureTask.run(FutureTask.java:138)
- atjava.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
- atjava.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
- atjava.lang.Thread.run(Thread.java:619)