码迷,mamicode.com
首页 > 其他好文 > 详细

ReentrantLock等待通知机制Condition介绍

时间:2019-02-16 11:58:08      阅读:161      评论:0      收藏:0      [点我收藏+]

标签:原理   repo   test   try   多个   rac   port   dstat   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配合使用。

ReentrantLock等待通知机制Condition介绍

标签:原理   repo   test   try   多个   rac   port   dstat   condition   

原文地址:https://www.cnblogs.com/sunshine-ground-poems/p/10387181.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!