JUC之Condition源码解析

定义

Condition主要是用来处理线程之间的通信,当满足某一条件时,唤醒其他的线程。
主要配合重入锁完成等待唤醒的操作。

案例

此demo定义了一个容量为5的数组。当数组容量达到容器最大容量时,写线程等待,读线程取走一个值,则唤醒写线程。同理,当容量为空时,读线程等待,写入一个值,则唤醒读线程。

public class ConditionTest {


    public static Object[] items = new Object[5];

    private ReentrantLock reentrantLock = new ReentrantLock();

    //条件对象,标记读线程
    private Condition empty = reentrantLock.newCondition();
	
    private Condition full = reentrantLock.newCondition();

    public void put() {
        reentrantLock.lock();
        try {
            while (count == items.length) {
                System.out.println("写线程等待");
                full.await();
            }

            count++;
            put++;
            //线程唤醒
            empty.signal();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            reentrantLock.unlock();
        }
    }

    public void take() {
        reentrantLock.lock();
        try {

            while (count == 0) {
                System.out.println("读线程等待");
                empty.await();
            }
            count--;
            take++;
            //线程唤醒
            full.signal();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            reentrantLock.unlock();
        }
    }


    public static void main(String[] args) {
        ConditionTest conditionTest = new ConditionTest();
        for (int i = 0; i < 10; i++) {
            new Thread(() -> {
                try {
                    Thread.sleep(1);
                    conditionTest.put();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

            }).start();
            new Thread(() -> {
                try {
                    Thread.sleep(10);
                    conditionTest.take();

                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }).start();
        }
    }
}

源码解析(线程等待)

  1. await()
        public final void await() throws InterruptedException {
        // 线程被打断,抛出异常
            if (Thread.interrupted())
                throw new InterruptedException();
             //将节点加入等待序列
            Node node = addConditionWaiter();
            //释放当前线程所占用的lock,在释放的过程中会唤醒同步队列中的下一个节点
            // 此处很好理解,如果不释放所占用的锁,则由于condition会堵塞当前线程,导致,其他
            //线程永远获取不到锁,也就导致了死锁。
            int savedState = fullyRelease(node);
            int interruptMode = 0;
            //自旋,检测节点是否已经进入堵塞队列
            while (!isOnSyncQueue(node)) {
               //线程挂起
                LockSupport.park(this);
                //线程被打断时退出自旋
                if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
                    break;
            }
            // 被唤醒后,将进入阻塞队列,等待获取锁,即重入锁的lock
            if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
                interruptMode = REINTERRUPT;
              //后续没有等待的下一节点,则清除该节点
            if (node.nextWaiter != null) // clean up if cancelled
                unlinkCancelledWaiters();
            if (interruptMode != 0)
            //线程中断的处理
                reportInterruptAfterWait(interruptMode);
        }

  1. addConditionWaiter()
		//加入等待队列
        private Node addConditionWaiter() {
        	//condition队尾元素
            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;
        }
  1. unlinkCancelledWaiters()
	//将已取消的所有节点清除出队列
        private void unlinkCancelledWaiters() {
            Node t = firstWaiter;
            Node trail = null;
            // 从头结点开始遍历,
            while (t != null) {
                Node next = t.nextWaiter;
                // 如果节点的状态不是CONDITION ,则说明该节点已取消
                if (t.waitStatus != Node.CONDITION) {
                	//断开连接
                    t.nextWaiter = null;
                    if (trail == null)
                    	//将下一个节点置为队首
                        firstWaiter = next;
                    else
                        trail.nextWaiter = next;
                    if (next == null)
                        lastWaiter = trail;
                }
                else
                    trail = t;
                t = next;
            }
        }
  1. fullyRelease()
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;
        }
    }
  1. isOnSyncQueue()
	//节点是否已经转移到阻塞队列
    final boolean isOnSyncQueue(Node node) {
    	// 如果当前节点的状态是CONDITION 或者没有前置节点,说明还没进入堵塞队列
        if (node.waitStatus == Node.CONDITION || node.prev == null)
            return false;
         //如果有下一节点说明已经进入堵塞队列
        if (node.next != null) // If has successor, it must be on queue
            return true;
            //从尾部节点查找该节点
        return findNodeFromTail(node);
    }

源码解析(线程唤醒)

唤醒之signal()

  1. signal()
        public final void signal() {
      	 // 调用 signal 方法的线程必须持有当前的独占锁
            if (!isHeldExclusively())
                throw new IllegalMonitorStateException();
             // 找到头结点
            Node first = firstWaiter;
            if (first != null)
            	//唤醒头结点
                doSignal(first);
        }
  1. doSignal()
    private void doSignal(Node first) {
    do {
    //自旋,从头结点开始寻找第一个能被唤醒的节点
    if ( (firstWaiter = first.nextWaiter) == null)
    lastWaiter = null;
    first.nextWaiter = null;
    } while (!transferForSignal(first) &&
    (first = firstWaiter) != null);
    }`

唤醒之signalAll()

  1. signalAll()
    public final void signalAll() {
    //同样检测
        if (!isHeldExclusively())
            throw new IllegalMonitorStateException();
        Node first = firstWaiter;
        if (first != null)
            doSignalAll(first);
    }

  1. doSignalAll()
        private void doSignalAll(Node first) {
            lastWaiter = firstWaiter = null;
            do {
            //自旋,从头到尾,依次唤醒
                Node next = first.nextWaiter;
                first.nextWaiter = null;
                transferForSignal(first);
                first = next;
            } while (first != null);
        }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值