submit和execute区别 二 (代码模式进行测试)

来源:互联网 发布:淘宝平面模特怎么找 编辑:程序博客网 时间:2024/05/20 18:51

先上测试用例

[java] view plain copy
  1. package com.phl.threadpool;  
  2. import java.util.concurrent.ExecutorService;  
  3. import java.util.concurrent.Executors;  
  4. import java.util.concurrent.Future;  
  5.   
  6. /** 
  7.  * @Title:SubmitExecuteMain 
  8.  * @Description: 
  9.  * @Copyright:中国电信爱wifi运营中心 
  10.  * @author:panhl 
  11.  * @date 2017/9/26 0026 10:34 
  12.  */  
  13. public class SubmitExecuteMain {  
  14.     public static void main(String[] args) throws Exception{  
  15.         submit();  
  16.         submitWithGet();  
  17.         execute();  
  18.     }  
  19.     private static void submitWithGet() throws Exception{  
  20.         ExecutorService service= Executors.newSingleThreadExecutor();  
  21.         Future future=service.submit(new Runnable() {  
  22.             @Override  
  23.             public void run() {  
  24.                 int i=7/0;  
  25.             }  
  26.         });  
  27.   
  28.          future.get();  
  29.   
  30.         service.shutdown();  
  31.     }  
  32.     private static void submit(){  
  33.         ExecutorService service= Executors.newSingleThreadExecutor();  
  34.         service.submit(new Runnable() {  
  35.             @Override  
  36.             public void run() {  
  37.                 int i=7/0;  
  38.             }  
  39.         });  
  40.   
  41.         service.shutdown();  
  42.     }  
  43.     private static void execute(){  
  44.         ExecutorService service= Executors.newSingleThreadExecutor();  
  45.         service.execute(new Runnable() {  
  46.             @Override  
  47.             public void run() {  
  48.                 int i=7/0;  
  49.             }  
  50.         });  
  51.         service.shutdown();  
  52.     }  
  53. }  

先下结论

1.对返回值的处理不同
execute方法不关心返回值。
submit方法有返回值,Future.
2.对异常的处理不同
excute方法会抛出异常。
sumbit方法不会抛出异常。除非你调用Future.get()

再看原理

当我们调用ExecutorService的submit的时候,其实是调用了
AbstractExecutorService.submit方法。直接看源码:
[java] view plain copy
  1. public Future<?> submit(Runnable task) {  
  2.        if (task == nullthrow new NullPointerException();  
  3.        RunnableFuture<Void> ftask = newTaskFor(task, null);  
  4.        execute(ftask);  
  5.        return ftask;  
  6. }  
 从上面的代码可以看出 execute和sumbit方法的不同在于这一行封装:
[java] view plain copy
  1. RunnableFuture<Void> ftask = newTaskFor(task, null);  
 这就是关键所在。

 先看execute方法

 当我们调用execute时,以ThreadPoolExecutor实现为例,他就是调用了ThreadPoolExecutor的execute方法。
[java] view plain copy
  1. public void execute(Runnable command) {  
  2.       if (command == null)  
  3.           throw new NullPointerException();  
  4.       int c = ctl.get();  
  5.       if (workerCountOf(c) < corePoolSize) {  
  6.           if (addWorker(command, true))  
  7.               return;  
  8.           c = ctl.get();  
  9.       }  
  10.       if (isRunning(c) && workQueue.offer(command)) {  
  11.           int recheck = ctl.get();  
  12.           if (! isRunning(recheck) && remove(command))  
  13.               reject(command);  
  14.           else if (workerCountOf(recheck) == 0)  
  15.               addWorker(nullfalse);  
  16.       }  
  17.       else if (!addWorker(command, false))  
  18.           reject(command);  
  19.   }  
    
这里不分析 execute方法内部实现,我想说的是ExecutorService的execute方法提交的任务被原模原样的的转交给了实现类ThreadPoolExecutor的execute方法。

也就是说原来提交的是Runnable,执行的也是Runnable.

具体提交任务流程不在这里作分析,最后直接看任务的执行代码:ThreadPoolExecutor.runWorker

[java] view plain copy
  1. final void runWorker(Worker w) {  
  2.     Thread wt = Thread.currentThread();  
  3.     Runnable task = w.firstTask;  
  4.     w.firstTask = null;  
  5.     w.unlock(); // allow interrupts  
  6.     boolean completedAbruptly = true;  
  7.     try {  
  8.         while (task != null || (task = getTask()) != null) {  
  9.             w.lock();  
  10.             if ((runStateAtLeast(ctl.get(), STOP) ||  
  11.                  (Thread.interrupted() &&  
  12.                   runStateAtLeast(ctl.get(), STOP))) &&  
  13.                 !wt.isInterrupted())  
  14.                 wt.interrupt();  
  15.             try {  
  16.                 beforeExecute(wt, task);  
  17.                 Throwable thrown = null;  
  18.                <strong> </strong>try {  
  19.                     task.run();  
  20.                 } catch (RuntimeException x) {  
  21.                     thrown = x; throw x;  
  22.                 } catch (Error x) {  
  23.                     thrown = x; throw x;  
  24.                 } catch (Throwable x) {  
  25.                     thrown = x; throw new Error(x);  
  26.                 } finally {  
  27.                     afterExecute(task, thrown);  
  28.                 }  
  29.             } finally {  
  30.                 task = null;  
  31.                 w.completedTasks++;  
  32.                 w.unlock();  
  33.             }  
  34.         }  
  35.         completedAbruptly = false;  
  36.     } finally {  
  37.         processWorkerExit(w, completedAbruptly);  
  38.     }  
  39. }  
真正执行的地方在task.run这一行,task 就是原模原样提交的Runnable,也就是执行了Runnable.run方法。有异常就抛异常

再看sumbit方法

sumbit方法的不同之处在于上面提到的那一行,对Runnable的封装。

[java] view plain copy
  1. RunnableFuture<Void> ftask = newTaskFor(task, null);  
直接看newTaskFor方法把 Runnable封装成了什么东西:
[java] view plain copy
  1. protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) {  
  2.         return new FutureTask<T>(runnable, value);  
  3. }  
  4. public FutureTask(Runnable runnable, V result) {  
  5.       this.callable = Executors.callable(runnable, result);  
  6.       this.state = NEW;       // ensure visibility of callable  
  7. }  
Runnable转变过程:
Runnable-----newTaskFor----->new FutureTask()------->FutureTask
任务的转变过程:
Runnable.run()-----Executors.callable(runnable, result)------->Callable.call()
通过上面两个方法,Runnable已经转变成了FutureTask。

关于FutureTask ,请参考我的另一篇博客:java-源码解读-FutureTask 

通过上面对execute方法的分析,我们知道runWorker 方法中那句task.run()其实也就是FutureTask.run()了。

直接看FutureTask.run()都干了什么:
[java] view plain copy
  1. public void run() {  
  2.     if (state != NEW ||  
  3.         !UNSAFE.compareAndSwapObject(this, runnerOffset,  
  4.                                      null, Thread.currentThread()))  
  5.         return;  
  6.     try {  
  7.         Callable<V> c = callable;  
  8.         if (c != null && state == NEW) {  
  9.             V result;  
  10.             boolean ran;  
  11.           <strong> </strong> try {  
  12.                 result = c.call();  
  13.                 ran = true;  
  14.             } catch (Throwable ex) {  
  15.                 result = null;  
  16.                 ran = false;  
  17.                 setException(ex);  
  18.             }  
  19.             if (ran)  
  20.                 set(result);  
  21.         }  
  22.     } finally {  
  23.         runner = null;  
  24.         int s = state;  
  25.         if (s >= INTERRUPTING)  
  26.             handlePossibleCancellationInterrupt(s);  
  27.     }  
  28. }  
代码很清楚,run方法中真正执行任务的地方为c.call(),也就是调用Callable.call(),当c.call()发生异常时 catch了,并调用了setExcetion方法:
[java] view plain copy
  1. protected void setException(Throwable t) {  
  2.        if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {  
  3.            outcome = t;  
  4.            UNSAFE.putOrderedInt(this, stateOffset, EXCEPTIONAL); // final state  
  5.            finishCompletion();  
  6.        }  
  7.    }  
setException把抛出的异常赋值给了outcome,outcome就是Futer.get() 的返回结果。
所以就有了开始的结论,submit提交任务时不会有异常,因为异常被当人作结果返回了。

要想submit方法也抛出异常,可以调用 Future.get(); Future的get 方法如下:

[java] view plain copy
  1.     public V get() throws InterruptedException, ExecutionException {  
  2.         int s = state;  
  3.         if (s <= COMPLETING)  
  4.             s = awaitDone(false, 0L);  
  5.         return report(s);  
  6.     }    
  7.     private V report(int s) throws ExecutionException {  
  8.         Object x = outcome;  
  9.         if (s == NORMAL)  
  10.             return (V)x;  
  11.         if (s >= CANCELLED)  
  12.             throw new CancellationException();  
  13. <strong>        throw new ExecutionException((Throwable)x);</strong>  
  14.     }  
原创粉丝点击