zoukankan      html  css  js  c++  java
  • Future & FutureTask

    一、What

     1. java创建多线程的方式

       a. Thread, 没有执行结果,既没有数据也没有异常

       b. ThreadPool,减少线程创建和销毁的开销

       c. Runnable,只有一个run()方法,没有执行结果,被Thread执行;如果要获得返回结果,可以使用共享变量或者线程通信的方法

       d. Callable,只有一个call()方法,是Runnable的补充,有返回值也有异常,返回的是泛型结果

       e. Future,先生成一个凭据而不是结果,不阻塞接下来的操作,然后通过凭据获取结果,用于异步计算

    2. FutureTask类实现了Future接口,是Future的一个基本实现

    3. 可以把Callable的实例作为FutureTask的参数,生成一个FutureTask的实例,把这个实例作为Runnable,作为参数启动一个线程

    二、How

    1. Callable接口, 配合ExecutorService里的submit()方法使用,是为了获取返回值

    2. Future接口,isDone()方法查看异步操作是否完成,get()方法返回结果,是为了异步

    3. FutureTask类

    a. 实现了Runnable接口和Future接口,综合了异步和返回结果的功能

    b. FutureTask的对象没有返回值,是一个Runnable;但是内部会把Runnable转换为Callable,有返回值;最终的返回值用get()方法获取,而不是直接返回

    c. 有一个回调函数done(),任务结束时会被触发;而Future没有此功能,只能判断任务是否结束,然后手动操作

     

    三、使用场景(When)

    1. 耗时计算,主线程完成自己的任务后,再获取子线程的计算结果

    2. 高并发环境下只执行一次,例如数据库链接的建立

    四、Why(原理)

    1. FutureTask的状态字段,表示当前线程的状态的转换

    * Possible state transitions:
         * NEW -> COMPLETING -> NORMAL
         * NEW -> COMPLETING -> EXCEPTIONAL
         * NEW -> CANCELLED
         * NEW -> INTERRUPTING -> INTERRUPTED
         */
        private volatile int state;
        private static final int NEW          = 0;
        private static final int COMPLETING   = 1;
        private static final int NORMAL       = 2;
        private static final int EXCEPTIONAL  = 3;
        private static final int CANCELLED    = 4;
        private static final int INTERRUPTING = 5;
        private static final int INTERRUPTED  = 6;

    2. FutureTask的run()方法源码,主要逻辑就是执行Callable的call()方法,把结果保存在全局变量里,相当于对Runnable的一次封装

    public void run() {
            if (state != NEW ||
                !UNSAFE.compareAndSwapObject(this, runnerOffset,
                                             null, Thread.currentThread()))
                return;
            try {
                Callable<V> c = callable; // 这里的callable是从构造方法里面传人的,虽然FutureTask的实例是Runnable,但最终使用的是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); // 保存call方法抛出的异常,而不是直接抛出
                    }
                    if (ran)
                        set(result); // 保存call方法的执行结果
                }
            } finally {
                // runner must be non-null until state is settled to
                // prevent concurrent calls to run()
                runner = null;
                // state must be re-read after nulling runner to prevent
                // leaked interrupts
                int s = state;
                if (s >= INTERRUPTING)
                    handlePossibleCancellationInterrupt(s);
            }
        }

     3. get()方法源码,使用死循环阻塞,直到从全局变量里拿到结果

    public V get() throws InterruptedException, ExecutionException {
            int s = state;
            if (s <= COMPLETING)
                s = awaitDone(false, 0L);
            return report(s);
    }
    
    private int awaitDone(boolean timed, long nanos)
            throws InterruptedException {
            final long deadline = timed ? System.nanoTime() + nanos : 0L;
            WaitNode q = null;
            boolean queued = false;
            for (;;) {
                if (Thread.interrupted()) {
                    removeWaiter(q);
                    throw new InterruptedException();
                }
    
                int s = state;
                if (s > COMPLETING) {
                    if (q != null)
                        q.thread = null;
                    return s;
                }
                else if (s == COMPLETING) // cannot time out yet
                    Thread.yield();
                else if (q == null)
                    q = new WaitNode();
                else if (!queued)
                    queued = UNSAFE.compareAndSwapObject(this, waitersOffset,
                                                         q.next = waiters, q);
                else if (timed) {
                    nanos = deadline - System.nanoTime();
                    if (nanos <= 0L) {
                        removeWaiter(q);
                        return state;
                    }
                    LockSupport.parkNanos(this, nanos);
                }
                else
                    LockSupport.park(this);
            }
    }

    参考:

    https://www.cnblogs.com/cz123/p/7693064.html

    https://www.jianshu.com/p/bce9301f1adb

  • 相关阅读:
    Quartz.NET 2.0 学习笔记(1) :Quartz.NET简介
    Quartz.NET 2.0 学习笔记(5) :实例创建Windows服务实现任务调度
    Quartz.NET 2.0 学习笔记(2) :和1.0的几点不同
    C#实现网页正文提取算法ok
    网页正文提取的思路
    sql getdate() 时间格式设置
    分页,静态程序asp实现,php同理
    网页正文抽取能用的抽取代码java
    泛采集技术
    查询一个数据表中的数据并插入到另一个数据表
  • 原文地址:https://www.cnblogs.com/june0816/p/7077405.html
Copyright © 2011-2022 走看看