先上测试用例
- package com.phl.threadpool;
- import java.util.concurrent.ExecutorService;
- import java.util.concurrent.Executors;
- import java.util.concurrent.Future;
-
-
-
-
-
-
-
-
- public class SubmitExecuteMain {
- public static void main(String[] args) throws Exception{
- submit();
- submitWithGet();
- execute();
- }
- private static void submitWithGet() throws Exception{
- ExecutorService service= Executors.newSingleThreadExecutor();
- Future future=service.submit(new Runnable() {
- @Override
- public void run() {
- int i=7/0;
- }
- });
-
- future.get();
-
- service.shutdown();
- }
- private static void submit(){
- ExecutorService service= Executors.newSingleThreadExecutor();
- service.submit(new Runnable() {
- @Override
- public void run() {
- int i=7/0;
- }
- });
-
- service.shutdown();
- }
- private static void execute(){
- ExecutorService service= Executors.newSingleThreadExecutor();
- service.execute(new Runnable() {
- @Override
- public void run() {
- int i=7/0;
- }
- });
- service.shutdown();
- }
- }
先下结论
1.对返回值的处理不同
execute方法不关心返回值。
submit方法有返回值,Future.
2.对异常的处理不同
excute方法会抛出异常。
sumbit方法不会抛出异常。除非你调用Future.get()
再看原理
当我们调用ExecutorService的submit的时候,其实是调用了
AbstractExecutorService.submit方法。直接看源码:
- public Future<?> submit(Runnable task) {
- if (task == null) throw new NullPointerException();
- RunnableFuture<Void> ftask = newTaskFor(task, null);
- execute(ftask);
- return ftask;
- }
从上面的代码可以看出 execute和sumbit方法的不同在于这一行封装:
- RunnableFuture<Void> ftask = newTaskFor(task, null);
这就是关键所在。
先看execute方法
当我们调用execute时,以ThreadPoolExecutor实现为例,他就是调用了ThreadPoolExecutor的execute方法。
- public void execute(Runnable command) {
- if (command == null)
- throw new NullPointerException();
- int c = ctl.get();
- if (workerCountOf(c) < corePoolSize) {
- if (addWorker(command, true))
- return;
- c = ctl.get();
- }
- if (isRunning(c) && workQueue.offer(command)) {
- int recheck = ctl.get();
- if (! isRunning(recheck) && remove(command))
- reject(command);
- else if (workerCountOf(recheck) == 0)
- addWorker(null, false);
- }
- else if (!addWorker(command, false))
- reject(command);
- }
这里不分析 execute方法内部实现,我想说的是ExecutorService的execute方法提交的任务被原模原样的的转交给了实现类ThreadPoolExecutor的execute方法。
也就是说原来提交的是Runnable,执行的也是Runnable.
具体提交任务流程不在这里作分析,最后直接看任务的执行代码:ThreadPoolExecutor.runWorker
- final void runWorker(Worker w) {
- Thread wt = Thread.currentThread();
- Runnable task = w.firstTask;
- w.firstTask = null;
- w.unlock();
- boolean completedAbruptly = true;
- try {
- while (task != null || (task = getTask()) != null) {
- w.lock();
- if ((runStateAtLeast(ctl.get(), STOP) ||
- (Thread.interrupted() &&
- runStateAtLeast(ctl.get(), STOP))) &&
- !wt.isInterrupted())
- wt.interrupt();
- try {
- beforeExecute(wt, task);
- Throwable thrown = null;
- <strong> </strong>try {
- task.run();
- } catch (RuntimeException x) {
- thrown = x; throw x;
- } catch (Error x) {
- thrown = x; throw x;
- } catch (Throwable x) {
- thrown = x; throw new Error(x);
- } finally {
- afterExecute(task, thrown);
- }
- } finally {
- task = null;
- w.completedTasks++;
- w.unlock();
- }
- }
- completedAbruptly = false;
- } finally {
- processWorkerExit(w, completedAbruptly);
- }
- }
真正执行的地方在task.run这一行,task 就是原模原样提交的Runnable,也就是执行了Runnable.run方法。
有异常就抛异常
。
再看sumbit方法
sumbit方法的不同之处在于上面提到的那一行,对Runnable的封装。
- RunnableFuture<Void> ftask = newTaskFor(task, null);
直接看newTaskFor方法把 Runnable封装成了什么东西:
- protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) {
- return new FutureTask<T>(runnable, value);
- }
- public FutureTask(Runnable runnable, V result) {
- this.callable = Executors.callable(runnable, result);
- this.state = NEW;
- }
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()都干了什么:
- public void run() {
- if (state != NEW ||
- !UNSAFE.compareAndSwapObject(this, runnerOffset,
- null, Thread.currentThread()))
- return;
- try {
- Callable<V> c = callable;
- if (c != null && state == NEW) {
- V result;
- boolean ran;
- <strong> </strong> try {
- result = c.call();
- ran = true;
- } catch (Throwable ex) {
- result = null;
- ran = false;
- setException(ex);
- }
- if (ran)
- set(result);
- }
- } finally {
- runner = null;
- int s = state;
- if (s >= INTERRUPTING)
- handlePossibleCancellationInterrupt(s);
- }
- }
代码很清楚,run方法中真正执行任务的地方为c.call(),也就是调用Callable.call(),当c.call()发生异常时 catch了,并调用了setExcetion方法:
- protected void setException(Throwable t) {
- if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {
- outcome = t;
- UNSAFE.putOrderedInt(this, stateOffset, EXCEPTIONAL);
- finishCompletion();
- }
- }
setException把抛出的异常赋值给了outcome,outcome就是Futer.get() 的返回结果。
所以就有了开始的结论,submit提交任务时不会有异常,因为异常被当人作结果返回了。
要想submit方法也抛出异常,可以调用 Future.get(); Future的get 方法如下:
- public V get() throws InterruptedException, ExecutionException {
- int s = state;
- if (s <= COMPLETING)
- s = awaitDone(false, 0L);
- return report(s);
- }
- private V report(int s) throws ExecutionException {
- Object x = outcome;
- if (s == NORMAL)
- return (V)x;
- if (s >= CANCELLED)
- throw new CancellationException();
- <strong> throw new ExecutionException((Throwable)x);</strong>
- }