跳至主要內容
  • Hostloc 空間訪問刷分
  • 售賣場
  • 廣告位
  • 賣站?

4563博客

全新的繁體中文 WordPress 網站
  • 首頁
  • 为啥 AQS 的 CondtionObject 的 firstWaiter 不需要是 volatile 的?
未分類
8 5 月 2020

为啥 AQS 的 CondtionObject 的 firstWaiter 不需要是 volatile 的?

为啥 AQS 的 CondtionObject 的 firstWaiter 不需要是 volatile 的?

資深大佬 : amiwrong123 8

其实关于这一点,网上大部分人都会说,要 await()必然要先 lock(),既然 lock()了就表示没有竞争,没有竞争自然也没必要使用 volatile+CAS 的机制去保证什么。所以 firstWaiter 不需要是 volatile 的。

但是实际上我感觉还是会有问题,比如你执行下面这段程序:

        final Lock lock=new ReentrantLock();         Condition Emptycondition = lock.newCondition();         Emptycondition.await();  //这样会抛出异常 

比如你让一个子线程去做上面的事,会抛出异常,因为 await()的时候没有获取锁呢。但是在抛出异常之前,你已经执行了一部分代码了:

        public final void await() throws InterruptedException {             if (Thread.interrupted())                 throw new InterruptedException();             Node node = addConditionWaiter();             int savedState = fullyRelease(node);//在这里抛出的异常,意味着已经执行了 addConditionWaiter             int interruptMode = 0;             while (!isOnSyncQueue(node)) {                 LockSupport.park(this);                 if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)                     break;             }             if (acquireQueued(node, savedState) && interruptMode != THROW_IE)                 interruptMode = REINTERRUPT;             if (node.nextWaiter != null) // clean up if cancelled                 unlinkCancelledWaiters();             if (interruptMode != 0)                 reportInterruptAfterWait(interruptMode);         }      final int fullyRelease(Node node) {         boolean failed = true;         try {             int savedState = getState();             if (release(savedState)) {//具体的说,是这里抛出异常了                 failed = false;                 return savedState;             } else {                 throw new IllegalMonitorStateException();             }         } finally {             if (failed)//抛出异常后,failed 为真,但善后处理只是将 node 的状态变成 CANCELLED                 node.waitStatus = Node.CANCELLED;         }     } 

再来看 addConditionWaiter 的逻辑:

        private Node addConditionWaiter() {             Node t = lastWaiter;             // If lastWaiter is cancelled, clean out.             if (t != null && t.waitStatus != Node.CONDITION) {                 unlinkCancelledWaiters();                 t = lastWaiter;             }                  Node node = new Node(Thread.currentThread(), Node.CONDITION);             if (t == null)                 firstWaiter = node;//对不保证可见性的变量进行赋值了             else                 t.nextWaiter = node;             lastWaiter = node;//对不保证可见性的变量进行赋值了             return node;         } 

好了,现在执行完我的那三行测试代码后,Emptycondition 的条件队列上有了一个 node,而且这个 node 包装了一个死掉的线程。因为抛出异常

现在假设有另一个线程执行正常流程的代码:

        final Lock lock=new ReentrantLock();         Condition Emptycondition = lock.newCondition();         lock.lock();         try{             Emptycondition.await();           } finally {             lock.unlock();         }          

现在条件是:

  1. 线程 A 执行 测试代码,会执行到 addConditionWaiter
  2. 线程 B 执行 正常流程代码,也会执行到 addConditionWaiter
  3. 两个线程可能同时执行 addConditionWaiter,却没有对 firstWaiter 进行 volatile+CAS 的保护,难道这样不会有问题吗?
大佬有話說 (11)

  • 資深大佬 : sagaxu

    因为你的代码没有做到要 await()必然要先 lock()

  • 主 資深大佬 : amiwrong123

    @sagaxu
    额,我好像没懂你意思。所以你想说 firstWaiter 不加 volatile,就会有问题呗

  • 資深大佬 : muyunn

    好长时间不用,差点被主绕进去,你必须先调用 lock.lock()获取锁,然后才可以 await

  • 資深大佬 : vk42

    lz 是想说不先 lock 的情况下后果不可控?但本来没按规则先 lock 不就是 bug 吗?直接修 bug 不是更简单么

  • 資深大佬 : luckyrayyy

    我的哥啊,你要研究一年 aqs ?

  • 主 資深大佬 : amiwrong123

    @muyunn
    是的,标准用法是这样

  • 主 資深大佬 : amiwrong123

    @vk42
    好吧,所以相当于决定权给了用户,作者默认使用者是按照正确用法使用的

  • 主 資深大佬 : amiwrong123

    @luckyrayyy
    哈哈哈,最近发帖太多被发现了吗。这几天 condition 的实现看完,就不看 aqs 了

  • 資深大佬 : yamasa

    佩服这牛角尖精神。虽然我觉得现行环境下死磕 jdk 源码不如刷 leetcode 来的现实。

  • 主 資深大佬 : amiwrong123

    @yamasa
    哎,所以我是又努力错方向了吗 ==

  • 資深大佬 : lux182

    我觉得如果你用最简洁的语言表述清楚了,可能你也就找到答案了

文章導覽

上一篇文章
下一篇文章

AD

其他操作

  • 登入
  • 訂閱網站內容的資訊提供
  • 訂閱留言的資訊提供
  • WordPress.org 台灣繁體中文

51la

4563博客

全新的繁體中文 WordPress 網站
返回頂端
本站採用 WordPress 建置 | 佈景主題採用 GretaThemes 所設計的 Memory
4563博客
  • Hostloc 空間訪問刷分
  • 售賣場
  • 廣告位
  • 賣站?
在這裡新增小工具