共同学习Java源代码-多线程与并发-FutureTask类(三)

来源:互联网 发布:js中数组 编辑:程序博客网 时间:2024/06/10 01:34
    static final class WaitNode {
        volatile Thread thread;
        volatile WaitNode next;
        WaitNode() { thread = Thread.currentThread(); }

    }

这个是静态终态内部类 将其他等待线程存储在这个链表结构的类里 


    private void finishCompletion() {
        // assert state > COMPLETING;
        for (WaitNode q; (q = waiters) != null;) {
            if (UNSAFE.compareAndSwapObject(this, waitersOffset, q, 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();


        callable = null;        // to reduce footprint
    }

这个方法是完成任务后的后续处理方法

先进入for循环遍历waitors 将waitors赋给循环变量q 

调用UNSAFE类的cas方法将waitors赋为空 如果这个方法返回true

再次进入一个内部for循环 

获取q也就是waitors 创建临时变量t 将q的thread属性赋给t

判断如果t不为空 也就是一个等待线程不为空 将q的thread属性置空 调用LockSupport的unpark方法 就是对线程进行解除阻塞 

然后判断如果q的下一个WaitNode为空就跳出内部for循环

将q的next属性置空 将q赋为下一个WaitNode节点 

最后跳出外部for循环

调用done方法这个模板方法 

最后将callable置空


    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);
        }
    }

这个方法是等待任务完成的方法

首先确定任务结束时间 判断第一个布尔值参数如果为true 截止日期就是当前日期加上第二个参数 否则就是0

创建WaitNode临时变量q赋为空 创建布尔值临时变量queued赋为false 

进入无限for循环

判断如果当前任务线程被打断 就调用removeWaitor方法删掉q 并抛出异常

然后判断状态不是NEW和COMPLETING 将q的thread属性置空 并返回状态

判断状态是COMPLETING 调用yield方法 让当前执行的线程变成就绪状态 

判断如果q为空 将q初始化为一个新的WaitNode

判断如果queued为false 调用UNSAFE的cas方法将q放在WaitNode链表第一位 代表不排队直接插队

判断如果timed为true 计算截止日期是否到了 如果到了 就调用removeWaiter方法 将q删除 并返回状态 如果时间没到 就调用LockSupport的parkNanos方法在剩余时间里阻塞本线程 

最后上述判断都不成立 就调用LockSupport的park方法阻塞住本线程


    private void removeWaiter(WaitNode node) {
        if (node != null) {
            node.thread = null;
            retry:
            for (;;) {          // restart on removeWaiter race
                for (WaitNode pred = null, q = waiters, s; q != null; q = s) {
                    s = q.next;
                    if (q.thread != null)
                        pred = q;
                    else if (pred != null) {
                        pred.next = s;
                        if (pred.thread == null) // check for race
                            continue retry;
                    }
                    else if (!UNSAFE.compareAndSwapObject(this, waitersOffset,
                                                          q, s))
                        continue retry;
                }
                break;
            }
        }
    }

这个是删除等待线程的方法

判断如果参数不为空 就将参数的thread属性置空 

进入名称为retry的无限for循环

进入内部for循环 循环变量pred为空 q赋为waiters s没有默认值 循环条件q不为空 一次循环结束后q赋为s

s赋为q的下一个节点 

判断如果q的thread属性不为空 将pred赋为q 

如果q的thread为空且pred不为空 pred的下一个节点赋为s 如果pred的thread属性为空 就continue名为retry的for循环

如果调用UNSAFE的cas方法将本对象的waiters设为s返回false的话 就continue名为retry的for循环

其实呢这个的原理就是 将参数节点的thread设为空 然后循环遍历时 将thread为空的节点删掉 内部循环结束了 就break外部循环


    private static final sun.misc.Unsafe UNSAFE;
    private static final long stateOffset;
    private static final long runnerOffset;
    private static final long waitersOffset;
    static {
        try {
            UNSAFE = sun.misc.Unsafe.getUnsafe();
            Class<?> k = FutureTask.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);
        }
    }

这个是UNSAFE的相关属性 其实就是state runner waiters的属性的内存地址

FutureTask讲解完毕

阅读全文
0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 她的沙雕又暴露了 在虐文里绑定了男主系统 我在末世成了领主大人 玄学老祖上综艺后轰动全球了 我继承了老公的神位 仵作掌中娇 世子爷她不可能是女的 穿进红楼后,我成了人生赢家 假死后夫人她称霸黑莲界 奶萌小团宠她觉醒了种田系统 巨星的大佬青梅 总裁的小撩精又生气了 开荒种田:农门辣妻有空间 签到后,小白花她在娱乐圈翻红了 江月照 魂飞魄散的上古大仙在修真界诈尸 快穿:大佬她又抢了反派剧本 夫人她总想逃 穿成阴戾反派未来嫂嫂 上神大人他偏甜系啊 咸鱼后妈带崽在综艺当对照组 系统BUG让我成了舔包专业户 快穿:系统有的是力气和手段 当我的霸总老公有了读心术 穿成炮灰渣妻后我和反派开农场 前任小姐姐帅又飒 弄潮1990从厂长开始 光阴之外 心动侵占 重回逃荒开端,手握空间来逆袭 重生之网红教父 蛮荒求生:反派大佬被迫种田 玄学大佬在星际重建地府 总裁又惹火夫人了 农门空间:重生娇娘撩糙汉 重生后我弃了天运之子 快穿:绑定系统后我疯狂崩人设 慕爷你虐错了夫人就是白月光 欢乐班 快穿之反派今天也在求负责 喜提娇夫:快穿作精她被迫崛起了