J.U.C之AQS:源码解析-响应中断

什么是中断

参考 线程的中断 & Interrupt

AQS如何响应

AQS响应中断的本质是让运行的线程能够从阻塞中唤醒并执行完毕。这其中包括2点

  • 1 线程能从阻塞中唤醒,AQS使用LockSupport.park(this)阻塞线程。而此方法是支持中断。

  • 2 线程能执行完毕正常退出,在AQS只有获取同步状态才能正常退出自旋循环。需要退出就需要在中断时抛出异常。

独占同步响应中断

/**
 * 功能同acquire,可以响应线程中断
 */
public final void acquireInterruptibly(int arg)
        throws InterruptedException {
    /** 测试当前线程是否已经中断(如果已经中断会将中断标识重新设置为false)**/
    if (Thread.interrupted())
        /** 抛出异常 **/
        throw new InterruptedException();
    /**
     *子类实现tryAcquire能否获取的独占式同步状态
     *如果返回true则获取同步状态成功方法直接返回
     *如果返回false则获取同步状态失败进入if语句
     */
    if (!tryAcquire(arg))
        /** 创建一个独占式节点node,添加到同步队列尾部.进入自旋,同步队列头部后置第一个节点线程尝试获取同步状态,成功则设置其为head节点.失败则阻塞
         * 如果发生中断,抛出异常线程退出自旋 **/
        doAcquireInterruptibly(arg);
}

/**
 * 独占获取同步状态,响应中断
 */
private void doAcquireInterruptibly(int arg)
    throws InterruptedException {
    /** addWaiter创建一个独占式节点node,添加到同步队列尾部.**/
    final Node node = addWaiter(Node.EXCLUSIVE);
    /** 执行是否发生异常 **/
    boolean failed = true;
    try {
        /** 进入自旋 **/
        for (;;) {
            /** 1. 获得当前节点的先驱节点  **/
            final Node p = node.predecessor();
            /** 如果当前节点的先驱节点是头结点并且成功获取同步状态 **/
            if (p == head && tryAcquire(arg)) {
                /** 并将当前节点设置为head节点  **/
                setHead(node);
                p.next = null; // help GC
                failed = false;
                return;
            }
            /** 2.2 获取锁失败,线程阻塞(可响应线程被中断),  如果是中断响应设置interrupted = true;
             * 抛出异常,中断导致退出自旋线程不在等待!!**/
            if (shouldParkAfterFailedAcquire(p, node) &&
                parkAndCheckInterrupt())
                throw new InterruptedException();
        }
    } finally {
        /** 发生异常,将当前节点等待状态设置为取消**/
        if (failed)
            cancelAcquire(node);
    }
}

共享同步响应中断

/**
 * 共享式获取同步状态,如果当前线程获取同步状态成功则直接返回,
 * 如果获取失败则线程阻塞,并插入同步队列进行.等待调用releaseShared
 * 释放同步状态时,重新尝试获取同步状态。成功则,同时会通知后置节点线程从阻塞中唤醒,
 * 获取同步状态并返回,失败则阻塞等待下次release
 */
public final void acquireShared(int arg) {
    /**
     *子类实现tryAcquireShared能否获取的共享式同步状态
     *如果返回>=0则获取同步状态成功方法直接返回
     *如果返回< 0则获取同步状态失败进入if语句
     */
    if (tryAcquireShared(arg) < 0)
        doAcquireShared(arg);
}


/**
 * 创建一个共享式节点node,添加到同步队列尾部.
 * 进入自旋,找到CLH头部后置第一个节点,尝试获取同步状态,成功则设置其为新head节点,
 * 并通知后置节点线程从阻塞中唤醒竞争同步状态.失败则阻塞.
 */
private void doAcquireShared(int arg) {
    /** 创建一个共享式节点node,添加到同步队列尾部..**/
    final Node node = addWaiter(Node.SHARED);
    /** 执行是否发生异常 **/
    boolean failed = true;
    try {
        /** 标识是否被中断 **/
        boolean interrupted = false;
        /** 进入自旋 **/
        for (;;) {
            /** 1. 获得当前节点的先驱节点  **/
            final Node p = node.predecessor();
            if (p == head) {
                /** 如果当前节点的先驱节点是头结点并且成功获取同步状态 **/
                int r = tryAcquireShared(arg);
                if (r >= 0) {
                    /** 将当前节点设置为head,同时只要同步队列中存在等待的节点,
                     * 且节点为共享节点则唤醒head节点后置节点阻塞去竞争同步状态. **/
                    setHeadAndPropagate(node, r);
                    p.next = null; // help GC
                    /** 如果当前线程中断 **/
                    if (interrupted)
                        /** 中断当前线程 **/
                        selfInterrupt();
                    failed = false;
                    return;
                }
            }
            /** 获取锁失败,在shouldParkAfterFailedAcquire中设置节点的等待状态,并线程阻塞(可响应线程被中断),
             * 如果是中断响应设置interrupted = true;
             * 抛出异常,中断导致退出自旋线程不在等待!!**/
            if (shouldParkAfterFailedAcquire(p, node) &&
                parkAndCheckInterrupt())
                interrupted = true;
        }
    } finally {
        /** 发生异常,将当前节点等待状态设置为取消**/
        if (failed)
            cancelAcquire(node);
    }
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,717评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,501评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,311评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,417评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,500评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,538评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,557评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,310评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,759评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,065评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,233评论 1 343
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,909评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,548评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,172评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,420评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,103评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,098评论 2 352

推荐阅读更多精彩内容