zoukankan      html  css  js  c++  java
  • Condition 实现原理

      Object 中可以通过 wait() 、notify() 来休眠唤醒。Condition 中同样可以实现这样的效果。

        static ReentrantLock lock = new ReentrantLock();
        static Condition condition = lock.newCondition();
    
        public static void main(String[] args) throws Exception{
            new Thread(()->{
                lock.lock();
                System.out.println("阻塞前的逻辑");
                try {
                    condition.await();
                }catch (Exception e){
                    e.printStackTrace();
                }
                System.out.println("阻塞后的逻辑");
                lock.unlock();
            }).start();
    
            Thread.sleep(2000L);
    
            new Thread(()->{
                lock.lock();
                System.out.println("唤醒线程");
                condition.signal();
                lock.unlock();
            }).start();
        }
    View Code

    await

    public final void await() throws InterruptedException {
        if (Thread.interrupted())
            throw new InterruptedException();
      
        //1. 当前线程将自己加入condition等待队列
        Node node = addConditionWaiter();
        
        //2. 挂起线程前,必须释放当前锁
        int savedState = fullyRelease(node);
        
        int interruptMode = 0; // 这里搞了个标志
        
        //3. 判断当前线程是否在同步队列中,如果不在同步队列,则直接挂起线程
        while (!isOnSyncQueue(node)) {
            LockSupport.park(this);
        
            // 如果线程被唤醒,线程节点从条件队列移除(就是cas将当前状态从-2改成0),并放到放到同步队列,或被中断
            if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
                break;
        }
        //4. 唤醒之后进入同步队列去竞争锁
        // 获取锁时中断,并且标志不是(响应中断)
        if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
            interruptMode = REINTERRUPT;
        if (node.nextWaiter != null) // clean up if cancelled
            
            //5. 清除等待队列中不是等待状态的节点
            unlinkCancelledWaiters();
        
        //6. 处理被中断的逻辑
        if (interruptMode != 0)
            reportInterruptAfterWait(interruptMode);
    }

    1. 刚开始 node 为空,就创建一个 node,状态为 Node.CONDITION

     2. 释放锁,首先获取到状态 savedstate 肯定是>0 因为被加过锁,现在会走 tryRelease 释放锁,将线程占用设置为null,最后走 aqs 的 unparkSuccessor 方法获取等待队列中的第一个线程,去唤醒他。

    3.  挂起自己,由于创建的时候自己状态是 CONDITION ,那就返回 false 通过 park(this) 把自己挂起来。

    signal

    已经写烂了,不想再写了 (传送门走起)。

  • 相关阅读:
    提高SQL查询效率
    数据库主键设计之思考
    Hlg 1030 排序
    Hdu 1556 成段更新.cpp
    Hdu 4280 最大流<模板>.cpp
    POJ 3216 最短路径匹配+floyd
    Hdu 4268 multiset函数的应用
    ZOJ 3602 树的同构
    Hdu 4284 状态DP 能否走完所选城市.cpp
    Hlg 1481 二分图匹配+二分.cpp
  • 原文地址:https://www.cnblogs.com/wlwl/p/15039814.html
Copyright © 2011-2022 走看看