资讯专栏INFORMATION COLUMN

ConditionObject源码阅读

xietao3 / 3374人阅读

摘要:前言本来准备做源码阅读的几千行看着太累了看了几篇大神的文章后才基本搞懂附在这里阅读本文前请先看懂的介绍和原理分析并发包源码学习之框架四源码分析接口实现接口一般看一个类实现的接口可以看出它的目的其实也是熟悉的目的主要是替代的方法的它是基于实现

前言

本来准备做AbstractQueuedSynchronizer源码阅读的,几千行看着太累了,看了几篇大神的文章后才基本搞懂,附在这里,阅读本文前请先看懂AQS

AbstractQueuedSynchronizer的介绍和原理分析

Java并发包源码学习之AQS框架(四)AbstractQueuedSynchronizer源码分析

Condition接口

ConditionObeject实现Condition接口,一般看一个类实现的接口可以看出它的目的,其实也是熟悉API.
Condition的目的主要是替代Object的wait,notify,notifyAll方法的,它是基于Lock实现的.(而Lock是来替代synchronized方法).

API
public interface Condition {

     /** 
      * 暂停此线程直至一下四种情况发生
      * 1.此Condition被signal()
      * 2.此Condition被signalAll()
      * 3.Thread.interrupt()
      * 4.伪wakeup
      * 以上情况.在能恢复方法执行时,当前线程必须要能获得锁
      */
    void await() throws InterruptedException;

 
    //跟上面类似,不过不响应中断
    void awaitUninterruptibly();

    //带超时时间的await()
    long awaitNanos(long nanosTimeout) throws InterruptedException;

    //带超时时间的await()
    boolean await(long time, TimeUnit unit) throws InterruptedException;
    
    //带deadline的await()
    boolean awaitUntil(Date deadline) throws InterruptedException;

    //唤醒某个等待在此condition的线程
    void signal();
  
    //唤醒所有等待在此condition的所有线程
    void signalAll();
}
AQS中的ConditionObject

此类的构造方法没有参数,所以不用讲
整体讲下这个ConditionObject的实现,其实其维护两个队列,

Condition队列,表示等待的队列,其waitStatus=Node.Condition,由firstWaiter和lastWaiter两个属性操控.

Sync队列,表示可以竞争锁的队列,这个跟AQS一致,waitStatus=0;

await()方法呢就是把当前线程创建一个Node加入Condition队列,接着就一致循环查其在不在Sync队列,如果当前节点在Sync队列里了,就可以竞争锁,恢复运行了.

signal()方法就是把某个节点的nextWaiter设为null,再把其从Condition队列转到Sync队列.
具体细节看下面源码及注释:

await()方法
  /**
   * 暂停此线程,直至许可满足
   * 只看没有中断和超时的await方法,其它处理中断和超时的逻辑不care   
   */
  public final void awaitUninterruptibly() {
    
            Node node = addConditionWaiter();
            //释放当前线程的锁
            int savedState = fullyRelease(node);
            boolean interrupted = false;
            //看自己在不在等待队列,在
            while (!isOnSyncQueue(node)) {
                //为了线程调度,禁用当前的线程,直到许可可用
                LockSupport.park(this);
                if (Thread.interrupted())
                    interrupted = true;
            }
            //获取刚才释放的锁,参考AQS中acquire的讲解吧
            if (acquireQueued(node, savedState) || interrupted)
                selfInterrupt();
        }
        
  /**
   * 添加一个等待Node到队列中   
   */
  private Node addConditionWaiter() {
            Node t = lastWaiter;
            // 如果尾节点被取消了,清理掉
            if (t != null && t.waitStatus != Node.CONDITION) {
                unlinkCancelledWaiters();
                t = lastWaiter;
            }
            // 新建一个Condition状态的节点,并将其加在尾部
            Node node = new Node(Thread.currentThread(), Node.CONDITION);
            if (t == null)
                firstWaiter = node;
            else
                t.nextWaiter = node;
            lastWaiter = node;
            return node;
        }
        
  /**
   * 释放当前的state,最终还是调用tryRelease方法
   */
  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)
                node.waitStatus = Node.CANCELLED;
        }
    }
    
  /**
   * 是否还需要等待
   */
  final boolean isOnSyncQueue(Node node) {
        //如果状态为Node.CONDITION,即还在Condition队列中,还得再循环中等待
        //如果其waitStatus不为Node.CONDITION,其前置节点,即Sync的前置节点为null,为啥也继续等着呢???谁来解答我的疑问
        if (node.waitStatus == Node.CONDITION || node.prev == null)
            return false;
        //如果状态不为Node.CONDITION,即不在Condition队列了,有前置节点也有后置节点,那么其一定在Sync队列
        if (node.next != null) 
            return true;
        /*
         * 其前置节点为非null,但是也不在Sync也是可能的,因为CAS将其加入队列失败.所以我们需要从尾部开始遍历确保其在队列
         */
        return findNodeFromTail(node);
    }
    /
    
    /**
     * 从尾部查找node节点
     */
    private boolean findNodeFromTail(Node node) {
        Node t = tail;
        for (;;) {
            if (t == node)
                return true;
            if (t == null)
                return false;
            t = t.prev;
        }
    }
signal()
/**
 * 释放信号
 */
 public final void signal() {
            //如果不是排它模式,则抛出IllegalMonitorStateException异常
            if (!isHeldExclusively())
                throw new IllegalMonitorStateException();
            //将等待队列的第一个节点出队列,并将其加入AQS的锁队列
            Node first = firstWaiter;
            if (first != null)
                doSignal(first);
 }
 
/**
 * 真正的释放信号
 */
private void doSignal(Node first) {
            do {
                //讲first的nextWaiter设为null
                if ( (firstWaiter = first.nextWaiter) == null)
                    lastWaiter = null;
                first.nextWaiter = null;
            }
            // 如果转换队列不成功且等待队列不为null,继续do
            while (!transferForSignal(first) &&
                     (first = firstWaiter) != null);
}

/**
 * 将一个节点从condition队列转换到Sync队列
 */
final boolean transferForSignal(Node node) {
        //所谓的Condition队列和Sync队列就在于waitStatus值
        if (!compareAndSetWaitStatus(node, Node.CONDITION, 0))
            return false;
        Node p = enq(node);
        int ws = p.waitStatus;
        if (ws > 0 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL))
            LockSupport.unpark(node.thread);
        return true;
}

/**
 * 唤醒所有等待在此condition的所有线程
 */
public final void signalAll() {
            if (!isHeldExclusively())
                throw new IllegalMonitorStateException();
            Node first = firstWaiter;
            if (first != null)
                doSignalAll(first);
}

/**
 * 遍历所有节点,使其加入到Sync队列
 */
private void doSignalAll(Node first) {
            lastWaiter = firstWaiter = null;
            do {
                Node next = first.nextWaiter;
                first.nextWaiter = null;
                transferForSignal(first);
                first = next;
            } while (first != null);
    }

在此输入正文

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/70093.html

相关文章

  • Java多线程框架源码阅读之---AQS的ConditionObject

    摘要:前置文章为,如果不了解的基本和实现机制,建议先看一下这个文章。类似于和,常用于实现生产者消费者。以下代码是一个用的做的一个生产者消费者例子。 前置文章为https://segmentfault.com/a/11...,如果不了解AQS的基本lock和unlock实现机制,建议先看一下这个文章。 Condition类似于wait和notify,notifyAll,常用于实现生产者消费者。...

    Tonny 评论0 收藏0
  • AbstractQueuedSynchronizer 原理分析 - Condition 实现原理

    摘要:实现原理是通过基于单链表的条件队列来管理等待线程的。中断在转移到同步队列期间或之后发生,此时表明有线程正在调用转移节点。在该种中断模式下,再次设置线程的中断状态。 1. 简介 Condition是一个接口,AbstractQueuedSynchronizer 中的ConditionObject内部类实现了这个接口。Condition声明了一组等待/通知的方法,这些方法的功能与Objec...

    leone 评论0 收藏0
  • AbstractQueuedSynchronizer 原理分析 - Condition 实现原理

    摘要:实现原理是通过基于单链表的条件队列来管理等待线程的。中断在转移到同步队列期间或之后发生,此时表明有线程正在调用转移节点。在该种中断模式下,再次设置线程的中断状态。 1. 简介 Condition是一个接口,AbstractQueuedSynchronizer 中的ConditionObject内部类实现了这个接口。Condition声明了一组等待/通知的方法,这些方法的功能与Objec...

    李世赞 评论0 收藏0
  • AbstractQueuedSynchronizer 原理分析 - Condition 实现原理

    摘要:实现原理是通过基于单链表的条件队列来管理等待线程的。中断在转移到同步队列期间或之后发生,此时表明有线程正在调用转移节点。在该种中断模式下,再次设置线程的中断状态。 1. 简介 Condition是一个接口,AbstractQueuedSynchronizer 中的ConditionObject内部类实现了这个接口。Condition声明了一组等待/通知的方法,这些方法的功能与Objec...

    bigdevil_s 评论0 收藏0
  • 源码分析JDK8之AbstractQueuedSynchronizer

    摘要:与之相关的方法有三个原子性地修改都是类型,可见我们可以进行,来定义的获取与释放从而实现我们自定义的同步器。 前言 源码分析我认为主要有两个作用:满足好奇心,我想每一个有追求的人都不会满足于仅仅做一个API Caller实现功能就好,我们也想知道它到底是怎么实现的;借鉴与升华,当我们明白了一个类的设计原理,在一定的情境下我们可以借鉴其设计哲学,甚至针对我们自己特殊的业务场景对其进行改良与...

    魏宪会 评论0 收藏0

发表评论

0条评论

xietao3

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<