阅读 86

线程池系列二:一张动图,彻底懂了execute和submit

我们知道线程池通过execute方法执行提交的Runnable任务,但Runnable只是执行任务,没有返回任何信息。

【线程池原理:线程池原来是个外包公司,打工人我悟了】

若是我们想在异步执行完任务后能够拿到结果。怎么处理呢?

我们可以借助Callable来回去返回结果。线程池为我们提供了另外一种方式执行任务,即submit方法

图片

1、为线程池提交任务

  • execute方法执行Runnable任务

  • submit方法执行Runnable或Callable任务,且能获取任务返回结果

图片

2、流程分解

2.1、execute方法执行Runnable任务

execute方法将Runnable任务交付给线程池执行

2.2、submit方法执行Runnable或Callable任务

2.2.1、创建futureTask对象(也是Runnable对象),包含属性Callable和object;将futureTask对象引用传递给外部

public class FutureTask<V> implements RunnableFuture<V> {
  
   /**
     * Possible state transitions:
     * NEW -> COMPLETING -> NORMAL
     * NEW -> COMPLETING -> EXCEPTIONAL
     * NEW -> CANCELLED
     * NEW -> INTERRUPTING -> INTERRUPTED
     */
    private volatile int state;
    /** The underlying callable; nulled out after running */
    private Callable<V> callable;
    /** The result to return or exception to throw from get() */
    private Object outcome; 
    
    public FutureTask(Callable<V> callable) {
        if (callable == null)
            throw new NullPointerException();
        this.callable = callable;
        this.state = NEW;
    }
  }复制代码

FutureTask中的状态属性(state)代表任务执行的进度。当任务执行到最终态时,代表任务执行结束。

后面调用get()方法时,判断到最终态才能获取object的值

2.2.2、若传入Runnable任务,将其转为Callable任务,赋值给Callable;

若传入Callable任务,则直接赋值给Callable

public static <T> Callable<T> callable(Runnable task, T result) {
    if (task == null)
         throw new NullPointerException();
    return new RunnableAdapter<T>(task, result);
}


/**
  * A callable that runs given task and returns given result
  */
static final class RunnableAdapter<T> implements Callable<T> {
    final Runnable task;
    final T result;
    RunnableAdapter(Runnable task, T result) {
         this.task = task;
         this.result = result;
     }
    public T call() {
         task.run();
         return result;
     }
 }复制代码

2.2.3、futureTask作为Runnable,execute方法执行此任务(见2.1)

2.2.4、当执行futureTask时,会调用其run方法执行Callable任务

Callable任务若正常返回结果则赋值给object;

若执行异常,则将异常捕获并赋值给object

图片

2.2.5、外部根据futureTask对象引用,调用get()方法,获取到futureTask中的object;区分是返回结果或异常进行处理

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);
    }复制代码

通过get()获取结果的过程:

  • 判断任务是否达到最终态。若达到,则根据状态将outcome值区分处理

  • 若未达到

    • 通过LockSupport.parkNanos(futureTask, nanos);挂起当前线程;

    • futureTask执行到最终态后会执行LockSupport.unpark(thread);重新恢复 因调用get()而挂起的线程

-----The End------

如果这个办法对您有用,或者您希望持续关注,也可以在微信公众号中搜索“码路无涯”**。


作者:zy苦行僧
链接:https://juejin.cn/post/7022171435749605406


文章分类
后端
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐