• FutureTask 解析


    参考自: https://www.cnblogs.com/linghu-java/p/8991824.html

    Future接口代表异步计算的结果,通过future提供的方法可以查看异步计算是否执行完成,或者等待执行结果并获取执行结果,同时还可以取消执行。

    futureTask表示的计算 是通过callable来实现的。有三种状态: 等待运行,正在运行,运行完成。执行完成 表示计算的所有可能结束方式,包括正常结束,由于取消而结束,由于异常而结束。

    Future.get的行为取决于任务的状态。

    FutureTask在Executor框架中表示异步任务,此外还可以用来表示一些时间较长的计算,这些计算可以在使用计算结果之前启动。

    FutureTask是future的实现类。

    FutureTask实现了RunnableFuture,runnableFuture接口继承自Runnable,Future

    成员变量:

    /**
     * The run state of this task, initially NEW.  The run state
     * transitions to a terminal state only in methods set,
     * setException, and cancel.  During completion, state may take on
     * transient values of COMPLETING (while outcome is being set) or
     * INTERRUPTING (only while interrupting the runner to satisfy a
     * cancel(true)). Transitions from these intermediate to final
     * states use cheaper ordered/lazy writes because values are unique
     * and cannot be further modified.
     
     state表示 任务的运行状态,初始时是new。只有调用set,setException,和cancel方法里,运行状态才能过度到终止状态。
     在完成任务期间,状态依赖在completing(当outcome被设置)或者被打断(只有当打断runner来满足一个取消事件)。从中间到最终状态的过度用便宜的有序的延迟写入。
     因为这些值是唯一的。并且将来不能被更改的。
     
     *
     * 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;
    
    /** The underlying callable; nulled out after running */
    //潜在的运行线程,在运行结束之后被设置成null
    private Callable<V> callable;
    // 这个就是保存线程运行之后的返回值的。可以是正常的返回或者是异常信息
    /** The result to return or exception to throw from get() */
    private Object outcome; // non-volatile, protected by state reads/writes
    //实际运行callable的线程对象。
    /** The thread running the callable; CASed during run() */
    private volatile Thread runner;
    //
    /** Treiber stack of waiting threads */
    private volatile WaitNode waiters;
    
    public void run() {
    // 判断状态是不是新的,如果是新的,那么则尝试把当前线程保存在runner字段中。
        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,并且设置异常信息。
                    result = null;
                    ran = false;
                    setException(ex);
                }
                if (ran)
                    set(result);
            }
        } 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);
        }
    }
    
    /**
     * Causes this future to report an {@link ExecutionException}
     * with the given throwable as its cause, unless this future has
     * already been set or has been cancelled.
     *
     使future抛出给出的异常,除非future已经被设置了异常或者被取消了。
     
     * <p>This method is invoked internally by the {@link #run} method
     * upon failure of the computation.
     *
     * @param t the cause of failure
     */
    protected void setException(Throwable t) {
        //这句话的意思就是如果当前线程的状态是new,那么将new改成completing,并且返回true,就继续执行if括号内的代码,反之,则直接返回了,不执行if中的代码了。
        if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {
            //将outcome设置成这个异常。
            outcome = t;
            //就是将当前的状态改成异常状态。
            UNSAFE.putOrderedInt(this, stateOffset, EXCEPTIONAL); // final state
            //设置成异常状态后,做完成状态的相关操作。
            finishCompletion();
        }
    }
    
    /**
     * Removes and signals all waiting threads, invokes done(), and
     * nulls out callable.
     
     清空所有waitNode。并唤醒所有等待的线程,执行done方法。
     */
    private void finishCompletion() {
        // assert state > COMPLETING;
        for (WaitNode q; (q = waiters) != null;) {
            //判断当前的waitnode是不是q,如果是,那么将当前waitnode改成null,并返回true。
            if (UNSAFE.compareAndSwapObject(this, waitersOffset, q, null)) {
                //通过自旋。就是死循环,来将waitNode中的线程都设置成null
                for (;;) {
                    Thread t = q.thread;
                    if (t != null) {
                        q.thread = null;
                        //唤醒线程。
                        LockSupport.unpark(t);
                    }
                    WaitNode next = q.next;
                    if (next == null)
                        break;
                    q.next = null; // unlink to help gc
                    q = next;
                }
                break;
            }
        }
        //执行done方法,done方法是个空方法,我们如果想自定义这个,可以覆盖这个方法。
        done();
    
        callable = null;        // to reduce footprint
    }
    
    /**
     * Makes available the permit for the given thread, if it
     * was not already available.  If the thread was blocked on
     * {@code park} then it will unblock.  Otherwise, its next call
     * to {@code park} is guaranteed not to block. This operation
     * is not guaranteed to have any effect at all if the given
     * thread has not been started.
     *
     如果给定的线程尚未可用,就使这个线程可用。 如果线程被阻塞在park方法,那么它就会变得不阻塞。否则,下一次call park方法时保证不会被阻塞。如果线程没有被启动,这个操作可以保证没有任何影响。
     
     其实就是唤醒这个线程,不让它等待。
     
     * @param thread the thread to unpark, or {@code null}, in which case
     *        this operation has no effect
     */
    public static void unpark(Thread thread) {
        if (thread != null)
            unsafe.unpark(thread);
    }
    
    /**
     * Protected method invoked when this task transitions to state
     * {@code isDone} (whether normally or via cancellation). The
     * default implementation does nothing.  Subclasses may override
     * this method to invoke completion callbacks or perform
     * bookkeeping. Note that you can query status inside the
     * implementation of this method to determine whether this task
     * has been cancelled.
     
     受保护的方法当任务改变状态到done时被调用,无论是正常的完成或者是被取消了。默认的实现是不做任何事。子类可以覆盖这个方法来调用完成的callback或者是执行记录。
     注意你可以在这个方法实现的内部查询状态来决定这个任务是否被取消了。
     
     */
    protected void done() { }
    
    /**
     * Ensures that any interrupt from a possible cancel(true) is only
     * delivered to a task while in run or runAndReset.
     
     保证从一个可能的取消事件的打断只能被发布到一个任务时当在运行时或者运行并且重置。
     */
    private void handlePossibleCancellationInterrupt(int s) {
        // It is possible for our interrupter to stall before getting a
        // chance to interrupt us.  Let's spin-wait patiently.
        if (s == INTERRUPTING)
            while (state == INTERRUPTING)
                Thread.yield(); // wait out pending interrupt
    
        // assert state == INTERRUPTED;
    
        // We want to clear any interrupt we may have received from
        // cancel(true).  However, it is permissible to use interrupts
        // as an independent mechanism for a task to communicate with
        // its caller, and there is no way to clear only the
        // cancellation interrupt.
        //
        // Thread.interrupted();
    }
    View Code
      1 /**
      2  * @throws CancellationException {@inheritDoc}
      3  
      4  阻塞方法
      5  */
      6 public V get() throws InterruptedException, ExecutionException {
      7     int s = state;
      8     if (s <= COMPLETING)
      9         s = awaitDone(false, 0L);
     10     return report(s);
     11 }
     12 
     13 private int awaitDone(boolean timed, long nanos)
     14         throws InterruptedException {
     15     // 计算等待截止时间
     16     final long deadline = timed ? System.nanoTime() + nanos : 0L;
     17     WaitNode q = null;
     18     boolean queued = false;
     19     for (;;) {
     20         // 1. 判断阻塞线程是否被中断,如果被中断则在等待队
     21         // 列中删除该节点并抛出InterruptedException异常
     22         if (Thread.interrupted()) {
     23             removeWaiter(q);
     24             throw new InterruptedException();
     25         }
     26  
     27         // 2. 获取当前状态,如果状态大于COMPLETING
     28         // 说明任务已经结束(要么正常结束,要么异常结束,要么被取消)
     29         // 则把thread显示置空,并返回结果
     30         int s = state;
     31         if (s > COMPLETING) {
     32             if (q != null)
     33                 q.thread = null;
     34             return s;
     35         }
     36         // 3. 如果状态处于中间状态COMPLETING
     37         // 表示任务已经结束但是任务执行线程还没来得及给outcome赋值
     38         // 这个时候让出执行权让其他线程优先执行
     39         else if (s == COMPLETING) // cannot time out yet
     40             Thread.yield();
     41         // 4. 如果等待节点为空,则构造一个等待节点
     42         else if (q == null)
     43             q = new WaitNode();
     44         // 5. 如果还没有入队列,则把当前节点加入waiters首节点并替换原来waiters
     45         else if (!queued)
     46             queued = UNSAFE.compareAndSwapObject(this, waitersOffset,
     47                     q.next = waiters, q);
     48         else if (timed) {
     49             // 如果需要等待特定时间,则先计算要等待的时间
     50             // 如果已经超时,则删除对应节点并返回对应的状态
     51             nanos = deadline - System.nanoTime();
     52             if (nanos <= 0L) {
     53                 removeWaiter(q);
     54                 return state;
     55             }
     56             // 6. 阻塞等待特定时间
     57             LockSupport.parkNanos(this, nanos);
     58         }
     59         else
     60             // 6. 阻塞等待直到被其他线程唤醒
     61             LockSupport.park(this);
     62     }
     63 }
     64 
     65 /**
     66  * Tries to unlink a timed-out or interrupted wait node to avoid
     67  * accumulating garbage.  Internal nodes are simply unspliced
     68  * without CAS since it is harmless if they are traversed anyway
     69  * by releasers.  To avoid effects of unsplicing from already
     70  * removed nodes, the list is retraversed in case of an apparent
     71  * race.  This is slow when there are a lot of nodes, but we don't
     72  * expect lists to be long enough to outweigh higher-overhead
     73  * schemes.
     74  尝试取消超时或者打断等待的node来避免堆积垃圾。
     75  内部节点没有CAS的简单非拼接的 因为如果他们被发布者遍历是有害的。
     76  为了避免影响从已经删除的节点非拼接,这个列表被重新遍历万一明显的竞争。
     77  当有很多节点时会很慢,但是我们不期望列表变得足够长以超过更高的开销方案。
     78  
     79  */
     80 private void removeWaiter(WaitNode node) {
     81     if (node != null) {
     82         node.thread = null;
     83         retry:
     84         for (;;) {          // restart on removeWaiter race
     85             for (WaitNode pred = null, q = waiters, s; q != null; q = s) {
     86                 s = q.next;
     87                 if (q.thread != null)
     88                     pred = q;
     89                 else if (pred != null) {
     90                     pred.next = s;
     91                     if (pred.thread == null) // check for race
     92                         continue retry;
     93                 }
     94                 else if (!UNSAFE.compareAndSwapObject(this, waitersOffset,
     95                                                       q, s))
     96                     continue retry;
     97             }
     98             break;
     99         }
    100     }
    101 }
    View Code

    下面是应用的例子

    package com.citi.test.mutiplethread.demo0503;
    
    import java.util.UUID;
    import java.util.concurrent.Callable;
    import java.util.concurrent.ExecutionException;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    import java.util.concurrent.Future;
    import java.util.concurrent.FutureTask;
    
    public class TestFutureTask {
        public static void main(String[] args) {
            //第一种方式 start
            {
                Worker worker=new Worker();
                ExecutorService newFixedThreadPool = Executors.newFixedThreadPool(10);
                Future<ProductInfo> submit = newFixedThreadPool.submit(worker);
                ProductInfo productInfo=null;
                try {
                    productInfo = submit.get();
                } catch (InterruptedException | ExecutionException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                System.out.println("第一种方式:"+productInfo);
                newFixedThreadPool.shutdown();
            }
            // 第一种方式 end
            
            {
                //第二种方式
                ExecutorService executor=Executors.newCachedThreadPool();
                Worker worker=new Worker();
                FutureTask<ProductInfo> futureTask=new FutureTask<ProductInfo>(worker);
                executor.submit(futureTask);
                ProductInfo productInfo=null;
                try {
                    productInfo = futureTask.get();
                } catch (InterruptedException | ExecutionException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                executor.shutdown();
                System.out.println("第二种方式:"+productInfo);
            }
            {
                //第三种方式
                FutureTask<ProductInfo> futureTask=new FutureTask<ProductInfo>(new Worker());
                Thread thread=new Thread(futureTask);
                thread.start();
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                try {
                    ProductInfo productInfo = futureTask.get();
                    System.out.println("第三种方式:"+productInfo);
                } catch (InterruptedException | ExecutionException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
            
        }
        
        static class Worker implements Callable<ProductInfo>{
            @Override
            public ProductInfo call() throws Exception {
    //            Thread.sleep(1000);s
                ProductInfo product=new ProductInfo();
                product.setName(UUID.randomUUID().toString());
                return product;
            }
            
        }
    }
    
    package com.citi.test.mutiplethread.demo0503;
    
    public class ProductInfo {
        private int id;
        private String name;
    
        public int getId() {
            return id;
        }
    
        public void setId(int id) {
            this.id = id;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public ProductInfo(int id, String name) {
            this.id = id;
            this.name = name;
        }
    
        public ProductInfo() {
        }
    
        @Override
        public String toString() {
            return "ProductInfo [id=" + id + ", name=" + name + "]";
        }
    
    }
    View Code
  • 相关阅读:
    Docker笔记(三):Docker安装与配置
    Docker笔记(二):Docker管理的对象
    Docker笔记(一):什么是Docker
    ubuntu18.04上搭建KVM虚拟机环境超完整过程
    软件项目研发流程该怎么规范
    线程池的基本原理,看完就懂了
    Spring Boot2从入门到实战:统一异常处理
    redission-tomcat:快速实现从单机部署到多机部署
    4. matlab入门——函数、绘图基础
    3. matlab入门——控制结构、选择结构、循环结构、错误控制
  • 原文地址:https://www.cnblogs.com/liumy/p/11607423.html
Copyright © 2020-2023  润新知