• FutureTask源码2


    @SuppressWarnings({"unchecked","restriction"}) 
    public class FutureTask1<V> implements RunnableFuture<V> {
        
        /* 
        任务可能出现的状态转换
        NEW新建 -> COMPLETING即将完成 -> NORMAL正常结束
        NEW新建 -> COMPLETING即将完成 -> EXCEPTIONAL异常
        NEW新建 -> CANCELLED被取消
        NEW新建 -> INTERRUPTING即将被中断 -> INTERRUPTED已经被中断
         
        第一种:初始化状态:NEW新建
        第二种:中间状态:COMPLETING即将完成,INTERRUPTING即将被中断
        第三种:终端状态:NORMAL正常结束,EXCEPTIONAL异常,CANCELLED被取消,INTERRUPTED已经被中断
        */
        private volatile int state;//任务当前状态,任务的状态可能被其他线程修改,所以要CAS。
        private static final int NEW = 0;//新建
        private static final int COMPLETING = 1;//即将完成。get(),finishCompletion(),awaitDone()使用这个状态。
        private static final int NORMAL = 2;//正常结束,返回结果值。report()使用这个变量。
        private static final int EXCEPTIONAL = 3;//异常,不返回结果值,抛出异常。没有使用这个状态。
        private static final int CANCELLED = 4;//被取消,不返回结果值,抛出异常。report(),isCanceld()方法使用这个变量。
        private static final int INTERRUPTING = 5;//即将被中断,不返回结果值,抛出异常。run()方法最后会使用这个状态。
        private static final int INTERRUPTED = 6;//已经被中断,不返回结果值,抛出异常。没有使用这个状态。
    
        //FutureTask里面只能是callable,即使传进来Runnable也会转换为callable,
        //也就是FutureTask真正执行的任务。Thread里面只能丢Runnable,要想FutureTask丢到线程池里面去,也必须是Runnable。
        //finishCompletion()置为null
        private Callable<V> callable;
        private Object outcome;//get()返回的结果
        private volatile Thread runner;//执行callable任务的线程,它是CAS操作。run()的最后finally置为null。
        private volatile WaitNode waiters;//等待结果的线程集合
    
        //根据状态s决定是否返回结果
        private V report(int s) throws ExecutionException {
            Object x = outcome;//我们在set()方法的时候把结果写进outcome的
            if (s == NORMAL)//只有是正常才返回结果。其余
                return (V) x;
            if (s >= CANCELLED)//CANCELLED4被取消,INTERRUPTING5即将被中断,INTERRUPTED6已经被中断,
                throw new CancellationException();
            throw new ExecutionException((Throwable) x);
        }
    
        //把Callable封装为FutureTask1
        public FutureTask1(Callable<V> callable) {
            if (callable == null)
                throw new NullPointerException();
            this.callable = callable;
            this.state = NEW; 
        }
    
        //把Runnable封装为FutureTask1,result是预期值。 
        public FutureTask1(Runnable runnable, V result) {
            this.callable = Executors1.callable(runnable, result);//runnbale封装为callable
            this.state = NEW;  
        }
    
        //判断是否取消了,包括cancel(false);和cancel(true);
        public boolean isCancelled() {
            return state >= CANCELLED;//CANCELLED被取消,INTERRUPTING即将被中断,INTERRUPTED已经被中断
        }
    
        //任务是否结束,不一定是成功任务,取消了,出异常了,被中断了,也是结束,包括cancel(false);和cancel(true);run(),setException(),set(),
        public boolean isDone() {
            return state != NEW;
        }
    
        //取消任务。如果是false  NEW0->CANCELLED4     true: NEW ->INTERRUPTING5->中断线程->INTERRUPTED6
        public boolean cancel(boolean mayInterruptIfRunning) {    
            //fasle&&:处于不是新建状态:返回fasle,状态不变。
            //true&&false:处于新建状态,但是状态设置失败:返回fasle,状态不变。
            if (!(state == NEW && UNSAFE.compareAndSwapInt(this, stateOffset, NEW, mayInterruptIfRunning ? INTERRUPTING : CANCELLED)))//即将被中断5,被取消4
                return false;
            //true&&true:是新建状态,并且 状态设置成功(将其置为INTERRUPTING5或者CANCELLED4):继续状态变为INTERRUPTED6
            try {  
                if (mayInterruptIfRunning) {//true才继续变为INTERRUPTED
                    try {
                        Thread t = runner;
                        if (t != null)
                            t.interrupt();//使用了线程中断的方法来达到取消任务的目的,设置中断标记=true
                    } finally { // final 已经被中断6
                        UNSAFE.putOrderedInt(this, stateOffset, INTERRUPTED);//6
                    }
                }
            } finally {
                finishCompletion();
            }
            return true;
        }
    
        //获取执行结果,阻塞,获得Callable的返回值
        public V get() throws InterruptedException, ExecutionException {
            int s = state;
            if (s <= COMPLETING)//COMPLETING1即将完成,NEW新建,如果任务还没执行完成,就等待任务先执行完成
                s = awaitDone(false, 0L);
            //s > COMPLETING:正常结束,异常,被取消,即将被中断,已经被中断
            return report(s);
        }
        
        //获取任务执行的结果,并且有超时机制
        public V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
            if (unit == null)
                throw new NullPointerException();
            int s = state;
             //带有超时时间的get(),如果超过指定时间,就会抛出一个TimeoutException
            if (s <= COMPLETING && (s = awaitDone(true, unit.toNanos(timeout))) <= COMPLETING)
                throw new TimeoutException();
            return report(s);
        }
    
        protected void done() {
        }
    
        protected void set(V v) {//先设置即将完成,再设置正常结束
            if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {//即将完成1
                outcome = v;//把任务执行的结果写入到outcome当中,
                UNSAFE.putOrderedInt(this, stateOffset, NORMAL); //final 正常结束2
                finishCompletion();//唤醒等待结果的线程
            }
        }
    
        //修改当前任务的状态
        protected void setException(Throwable t) {//先设置即将完成,再设置异常
            if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {//即将完成1
                outcome = t;//把任务执行的结果写入到outcome当中,
                UNSAFE.putOrderedInt(this, stateOffset, EXCEPTIONAL); // final 异常3
                finishCompletion();//唤醒等待结果的线程
            }
        }
        
        //任务起动就调这个方法。
        public void run() {
            //true||:不是新建,已经执行了,就不执行
            //fasle||true:是新建,runner设置当前线程失败了,就不执行
            if (state != NEW || !UNSAFE.compareAndSwapObject(this, runnerOffset, null, Thread.currentThread()))//不能多线程进来
                return;
            //false||fasle:是新建,设置runner成功就进去
            try {
                Callable<V> c = callable;
                if (c != null && state == NEW) {
                    V result;
                    boolean ran;
                    try {
                        result = c.call();//Callable的call方法,如果是Runnable封装的Callable,call方法返回的是RunnableAdapter的期望值。
                        ran = true;
                    } catch (Throwable ex) {//call()抛出了异常
                        result = null;
                        ran = false;
                        setException(ex);//状态不是NEW就不设置异常结果。先设置即将完成,再设置异常。设置1 3
                    }
                    if (ran)
                        set(result);//设置结果,状态不是NEW就不设置结果。先设置即将完成,再设置正常结束。设置1 2。
                }
            } finally {
                //在任务执行的过程中,可能会调用cancel(),这里主要是不想让中断操作逃逸到run()方法之外
                runner = null;//可以多线程进来了
                int s = state;
                if (s >= INTERRUPTING)//即将被中断5和已经被中断6。调用了cancel(true)现在s=5|6。调用cancel(false)=4不会进来。
                    handlePossibleCancellationInterrupt(s);
            }
        }
    
        protected boolean runAndReset() {
            if (state != NEW || !UNSAFE.compareAndSwapObject(this, runnerOffset, null, Thread.currentThread()))
                return false;
            boolean ran = false;
            int s = state;
            try {
                Callable<V> c = callable;
                if (c != null && s == NEW) {
                    try {
                        c.call(); // don't set result
                        ran = true;
                    } catch (Throwable ex) {
                        setException(ex);
                    }
                }
            } finally {
                //在任务执行的过程中,可能会调用cancel(),这里主要是不想让中断操作逃逸到run()方法之外
                runner = null;
                s = state;
                if (s >= INTERRUPTING)//INTERRUPTING5即将被中断,INTERRUPTED6已经被中断。调用了cancel(true)。
                    handlePossibleCancellationInterrupt(s);
            }
            return ran && s == NEW;
        }
    
        private void handlePossibleCancellationInterrupt(int s) {
            if (s == INTERRUPTING)//5,如果cancel(true)并且现在是5
                while (state == INTERRUPTING)
                    Thread.yield(); // 避免过多的CPU时间放在这个for循环的自旋上,让步等着变为INTERRUPTED6,等着runner线程被设置中断标记在退出,就是在收集cancel(true)的中断标记再出去//         assert state == INTERRUPTED;
            // 清除cancel(true)的中断,中断是任务task和调用者通信的机制, 
            // Thread.interrupted();   //重置中断状态为未中断=false;    isInterrupted不会重置中断状态;
        }
    
        static final class WaitNode {
            volatile Thread thread;
            volatile WaitNode next;//下一个
    
            WaitNode() {
                thread = Thread.currentThread();
            }
        }
    
        //成功|取消 完成任务后唤醒等待结果的线程。cancel()设置s=4|6后调用这个方法,run()正常完成设置s=2,run()异常完成设置s=3后调用这个方法。
        //awaitDone()唤醒的线程走if(s > COMPLETING1)返回状态值去get()获取结果。
        private void finishCompletion() {
             assert state > COMPLETING;//正常结束,异常,被取消,即将被中断,已经被中断
            for (WaitNode q; (q = waiters) != null;) {//从头开始唤醒
                
                //设置为null之后,其他get线程看到状态>1,直接获取结果,不加入waiters队列。
                //如果其他线程成功加入到了另一个新的waiters队列,此时唤醒失败,就要另一个线程他自己去退出。
                //这里准备开始清空等待队列了,就要阻止其他线程进到队列来(通过状态值),如果清空后还是进到队列去了,就要线程自己处理。
                if (UNSAFE.compareAndSwapObject(this, waitersOffset, q, null)) {
                    for (;;) {
                        Thread t = q.thread;
                        if (t != null) {
                            q.thread = null;//thread属性置为null
                            LockSupport.unpark(t);//唤醒的是获取结果的awaitDone()阻塞的线程
                        }
                        WaitNode next = q.next;
                        if (next == null)
                            break;
                        q.next = null; //gc q,q.next不会回收,因为还有next指向在。
                        System.gc();
                        System.gc();
                        System.gc();
                        System.gc();
                        System.gc();
                        q = next;
                    }
                    break;
                }
            }
            //一个钩子方法,本类中,它是一个空实现,在子类中可以重写它。
            done();
            //最后把callable置为null.
            callable = null; // to reduce footprint
        }
    
        //等待任务完成,多线程进来,唤醒之后,返回状态去get获取结果。2个出口。
        private int awaitDone(boolean timed, long nanos) throws InterruptedException {
            final long deadline = timed ? System.nanoTime() + nanos : 0L;//超时时间,如果使用了超时的get()才起作用,否则这个值不起作用
            WaitNode q = null;
            boolean queued = false;
            for (;;) {
                if (Thread.interrupted()) {//等待结果的线程被中断了 
                    removeWaiter(q);//移除无效节点
                    throw new InterruptedException();//就抛出一个中断异常
                }
                
                /*分为几部操作:每一步都在一个for循环里面,只有前面一步执行了才能在下一个循环里面执行下一步*/
                
                int s = state; 
                
                //如果当前状态大于COMPLETING,说明任务已经正常完成了或者取消完成了。就去拿结果。拿到的结果可能是null就抛出异常。
                //NORMAL正常结束,EXCEPTIONAL异常,CANCELLED被取消,INTERRUPTING即将被中断,INTERRUPTED已经被中断
                if (s > COMPLETING) {
                    if (q != null) 
                        q.thread = null;//回收q.thread
                    return s;//返回任务的状态,等待结束。有可能是cancel()设置s=4|6后唤醒,有可能是run()设置s=2后唤醒,run()设置s=3后唤醒。
                    
                // 正在完成,先等一会,下次循环去初始化节点--压栈--阻塞    
                } else if (s == COMPLETING) 
                    Thread.yield();//避免过多的CPU时间放在这个for循环的自旋上。再次判断状态。
                
                else if (q == null)//初始化q节点,才能去压栈,才能去阻塞。(后面2步在下一个循环中处理,会跳过这个循环)
                    q = new WaitNode();//再次判断状态。
                
                else if (!queued)//将q节点压入栈,它是一个cas操作。第一次是false,压栈成功变为true,再去阻塞。也就是说只有压栈了才能去阻塞。后来的在前面。
                    //有可能唤醒不了:finishCompletion()已经执行完了,才加入到队列就不能唤醒,就加入到一个新的waiters里面去了,就要再次循环,通过状态退出。
                    queued = UNSAFE.compareAndSwapObject(this, waitersOffset, q.next = waiters, q);
                    //再次判断状态。
                else if (timed) {//如果有超时限制的话,判断是否超时,如果没有超时就重试,如果超时了,就把q节点从栈中遇除
                    nanos = deadline - System.nanoTime();
                    if (nanos <= 0L) {//超时了
                        removeWaiter(q);//移除无效节点,多线程进来
                        return state;//返回状态,去获取结果。
                    }
                    LockSupport.parkNanos(this, nanos);//LockSupport是一个并发工具,这里表示等待nanos秒后唤醒
                } else
                    LockSupport.park(this);//开始阻塞线程,直到任务完成了才会再次唤醒了在finishCompletion()中唤醒
            }
        }
    
        /* 
          将某个节点置为无效节点,并清除栈中所有的无效节点
         (通过前面的分析,应该可以推断出,无效的节点,其实就是指节点内部的thread == null) 
          那么产生无效节点的情况就有三种了
            (1):线程被中断了
            (2):s > COMPLETING,当前的任务状态> COMPLETING
            (3):超时
         */
        //如果在阻塞其间,任务被中断了,或者超时了,又或者任务已经完成了,都需要进行资源的回收。
        private void removeWaiter(WaitNode node) {
            if (node != null) {
                node.thread = null;//为了GC回收node节点中的thread成员变量
                retry: 
                    for (;;) {//从头到尾删除thread=null的。不仅仅删除node。
                        
                        /* 多线程不会有影响,其他线程只是做了重复的事情,或者可以帮着其他线程做  */
                        
                        for (WaitNode pred = null, q = waiters, s; q != null; q = s) {
                            s = q.next; 
                            if (q.thread != null)
                                pred = q;//q不为null,pred只要被赋值了就不为null。
                            else if (pred != null) {
                                pred.next = s;
                                if (pred.thread == null)  
                                    continue retry;//如果前驱节点也是一个无效节点,则重新遍历,
                                
                            //q.thread异常了,pred=null,说明pred没有被赋值过,第一个q就异常了。
                            } else if (!UNSAFE.compareAndSwapObject(this, waitersOffset, q, s))//修改头结点是多线程在修改。修改失败就重来。
                                continue retry;//调到外层循环再来。
                        }
                        break;
                }
            }
        }
    
        private static final sun.misc.Unsafe UNSAFE;
        private static final long stateOffset;//state
        private static final long runnerOffset;//runner
        private static final long waitersOffset;//waiters
        static {
            try {
                UNSAFE = java.security.AccessController
                        .doPrivileged(new java.security.PrivilegedExceptionAction<sun.misc.Unsafe>() {
                            public sun.misc.Unsafe run() throws Exception {
                                Class<sun.misc.Unsafe> k = sun.misc.Unsafe.class;
                                for (java.lang.reflect.Field f : k.getDeclaredFields()) {
                                    f.setAccessible(true);
                                    Object x = f.get(null);
                                    if (k.isInstance(x))
                                        return k.cast(x);
                                }
                                throw new NoSuchFieldError("the Unsafe");
                            }
                        });
                Class<?> k = FutureTask1.class;
                stateOffset = UNSAFE.objectFieldOffset(k.getDeclaredField("state"));
                runnerOffset = UNSAFE.objectFieldOffset(k.getDeclaredField("runner"));
                waitersOffset = UNSAFE.objectFieldOffset(k.getDeclaredField("waiters"));
            } catch (Exception e) {
                throw new Error(e);
            }
        }
    
    }
  • 相关阅读:
    常见字体图标库——font-awesome
    windows server 2012显示桌面图标
    SE 2014年4月14日
    SE 2014年4月13日
    PPP协议总结
    SE 2014年4月12日
    django运行时报错
    linux-python在vim下的自动补全功能
    python发邮件
    背景透明兼容
  • 原文地址:https://www.cnblogs.com/yaowen/p/11388074.html
Copyright © 2020-2023  润新知