java-源码解读-线程池提交之execute和submit有何不同

先上测试用例

package com.phl.threadpool;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

/**
 * @Title:SubmitExecuteMain
 * @Description:
 * @Copyright:中国电信爱wifi运营中心
 * @author:panhl
 * @date 2017/9/26 0026 10:34
 */
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;
            }
        });
    service.shutdown();
    future.get(); 
}
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(); // allow interrupts
        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;
                    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;       // ensure visibility of callable
}
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;
                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); // final state
            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();
        throw new ExecutionException((Throwable)x);
    }
  • 9
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值