zoukankan      html  css  js  c++  java
  • ReentrantLock等待通知机制Condition介绍

      Object类中的wait(),notify()和notifyAll()可以实现线程的等待通知模型,同样在ReentrantLock中可以借助Condition来完成这种机制。本篇就简要介绍Condition的工作原理。

      先看一下Condition的使用示例:

    public class LockConditionTest {
        private ReentrantLock lock = new ReentrantLock();
        private Condition condition = lock.newCondition();
        /**
         * 等待方法
         */
        private void startAwait() {
            try {
                lock.lock(); 
                System.out.println("开始等待:" + System.currentTimeMillis());
                condition.await(); 
                System.out.println("等待结束:" + System.currentTimeMillis());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }finally{
                lock.unlock();
            }
        }
        
        /**
         * 释放方法
         */
        private void startSignal() {
            try {
                lock.lock();
                System.out.println("开始释放");
                condition.signal();
            } catch (Exception e) {
                e.printStackTrace();
            }finally {
                //这里锁被主线程持有,必须释放,让被唤醒的MyThread能够得到锁
                lock.unlock();
            }
        }
        
        
        public static void main(String[] args) throws InterruptedException {
            LockConditionTest test = new LockConditionTest();
            MyThread myThread = new LockConditionTest().new MyThread(test);
            //开始线程。 让线程等待。
            myThread.start();
            //myThread调用condition.await()释放锁,main线程开始执行
            TimeUnit.MILLISECONDS.sleep(1000);
            //主线程唤醒等待线程
            test.startSignal();
        }
        
        
        class MyThread extends Thread{
            private LockConditionTest test;
            
            public MyThread(LockConditionTest test) {
                this.test = test;
            }
    
            @Override
            public void run() {
                //开始等待,释放锁
                test.startAwait();
            }
        }
        
    }

      这段代码的输出为:

    开始等待:1550285191899
    开始释放
    等待结束:1550285192902
    

      等待时间大概为1000毫秒,符合预期。

      

    下面看看Condition的await()方法:

    public final void await() throws InterruptedException {
                if (Thread.interrupted())
                    throw new InterruptedException();
                Node node = addConditionWaiter();    // 1
                int savedState = fullyRelease(node);  // 2
                int interruptMode = 0;
                while (!isOnSyncQueue(node)) {
                    LockSupport.park(this);   // 3
                    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);
            }

      主要分为3步:

    1. 把当前线程封装为一个Node节点,把节点加入等待队列
    2. fullyRelease()方法,释放锁
    3. 用LockSupport.park()挂起当前线程

    再看看signal()方法:

    public final void signal() {
                if (!isHeldExclusively())
                    throw new IllegalMonitorStateException();
                Node first = firstWaiter;    // 1
                if (first != null)
                    doSignal(first);
            }
    
    private void doSignal(Node first) {
                do {
                    if ( (firstWaiter = first.nextWaiter) == null)
                        lastWaiter = null;
                    first.nextWaiter = null;
                } while (!transferForSignal(first) &&
                         (first = firstWaiter) != null);
            }
    
    final boolean transferForSignal(Node node) {
            if (!compareAndSetWaitStatus(node, Node.CONDITION, 0))    // 2
                return false;
    
            Node p = enq(node);
            int ws = p.waitStatus;
            if (ws > 0 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL))
                LockSupport.unpark(node.thread);           // 3 
            return true;
        }
    1. 从这段代码可以看到,signal()是唤醒等待队列中的第一个线程
    2. CAS更新节点状态
    3. 唤醒此节点代表的线程

      如果要唤醒全部线程,可以调用signalAll()方法。如果想唤醒部分线程,可以实例化多个Condition配合使用。

  • 相关阅读:
    antd表单不显示label和冒号
    create-react-app 区分环境 环境变量
    在actionCreator中使用getState,数据格式是immutable
    给树状数据添加层级id
    vscode中的正则搜索与替换演示,删除对象中不要的属性及属性值
    http-proxy-middleware做代理时,自定义复杂的匹配规则
    antd省市区级联
    axios封装
    jmeter-07-参数化-关联(json提取)
    jmeter-06-参数化-csv参数化
  • 原文地址:https://www.cnblogs.com/sunshine-ground-poems/p/10387181.html
Copyright © 2011-2022 走看看