CountDownLatch浅析

假如有4个线程ABCD,其中A、B需要等待C、D执行到某个点后再执行,那么就可以使用CountDownLatch实现。

主要方法
	初始化方法,会初始化Sync的内部变量state,
	public CountDownLatch(int count) {
        if (count < 0) throw new IllegalArgumentException("count < 0");
        this.sync = new Sync(count);
    }
	state代表资源数
	Sync(int count) {
        setState(count);
    }
    protected final void setState(int newState) {
        state = newState;
    }
    
  1. countDown
    当countdownlatch的countdown方法被执行state次后,执行await方法的线程会被唤醒继续执行。
 	public void countDown() {
        sync.releaseShared(1);
    }

    public final boolean releaseShared(int arg) {
    	判断state值是否等于0,等于0会调用doReleaseShared方法,唤醒因await方法阻塞的线程
        if (tryReleaseShared(arg)) {
            doReleaseShared();
            return true;
        }
        return false;
    }
    释放资源会循环调用cas方法将state的值减1,如果最后state==0,返回true,说明countdown方法执行完了,state=0
	protected boolean tryReleaseShared(int releases) {
            // Decrement count; signal when transition to zero
            for (;;) {
                int c = getState();
                if (c == 0)
                    return false;
                int nextc = c - 1;
                if (compareAndSetState(c, nextc))
                    return nextc == 0;
            }
        }

     private void doReleaseShared() {
        for (;;) {
            进入循环后,取得当前队列头节点线程,
            Node h = head;
            头节点存在并且队列中存在两个节点以上,说明至少一个线程节点进入了队列
            if (h != null && h != tail) {
            	获取线程状态
                int ws = h.waitStatus;
                如果是SIGNAL状态,就尝试设置线程状态为0,并唤醒后继节点线程
                if (ws == Node.SIGNAL) {
                    if (!h.compareAndSetWaitStatus(Node.SIGNAL, 0))
                        continue;            // loop to recheck cases
                    unparkSuccessor(h);
                }
                
                else if (ws == 0 &&
                         !h.compareAndSetWaitStatus(0, Node.PROPAGATE))
                    continue;                // loop on failed CAS
            }
            
            if (h == head)                   // loop if head changed
                break;
        }
    }
	唤醒后继节点线程方法
	private void unparkSuccessor(Node node) {
        int ws = node.waitStatus;
        if (ws < 0)
            node.compareAndSetWaitStatus(ws, 0);
            
		获取后继节点
        Node s = node.next;
        后继节点有效则直接唤醒,无效则从队列尾部开始向前找到一个靠近队首的有效节点
        if (s == null || s.waitStatus > 0) {
            s = null;
            for (Node p = tail; p != node && p != null; p = p.prev)
                if (p.waitStatus <= 0)
                    s = p;
        }
        if (s != null)
            LockSupport.unpark(s.thread);
    }
  1. await方法
 	public void await() throws InterruptedException {
        sync.acquireSharedInterruptibly(1);
    }
    
    public final void acquireSharedInterruptibly(int arg)
            throws InterruptedException {
        if (Thread.interrupted())
            throw new InterruptedException();
         state未减到0,执行doAcquireSharedInterruptibly方法,否则继续执行线程后面的代码
        if (tryAcquireShared(arg) < 0)
            doAcquireSharedInterruptibly(arg);
    }
    
     private void doAcquireSharedInterruptibly(int arg)
        throws InterruptedException {
        将线程放入队列,队列不存在还会初始化(会创建虚拟头节点,waitstates是0final Node node = addWaiter(Node.SHARED);
        try {
            for (;;) {
            	获取当前线程的前一个线程节点
                final Node p = node.predecessor();
                前驱结点为头节点,尝试获取资源
                if (p == head) {
                    int r = tryAcquireShared(arg);
                    r>=0,说明countdown已经减为0了,当前线程可以继续执行后面的方法
                    if (r >= 0) {
                    	将当前节点线程设置为头节点,唤醒后面的线程
                        setHeadAndPropagate(node, r);
                        p.next = null; // help GC,回收节点
                        return;
                    }
                }
         将当前线程放在一个状态有效的线程节点后面,如果前驱节点已经是signal状态,则可以阻塞当前线程
                if (shouldParkAfterFailedAcquire(p, node) &&
                    parkAndCheckInterrupt())
                    throw new InterruptedException();
            }
        }
        响应线程中断 
		catch (Throwable t) {
            cancelAcquire(node);
            throw t;
        }
    }
     private void setHeadAndPropagate(Node node, int propagate) {
        Node h = head; // Record old head for check below
        设置新的头节点
        setHead(node);
        if (propagate > 0 || h == null || h.waitStatus < 0 ||
            (h = head) == null || h.waitStatus < 0) {
            获取下一个线程节点,尝试唤醒
            Node s = node.next;
            if (s == null || s.isShared())
                doReleaseShared();
        }
    }

	 private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
        int ws = pred.waitStatus;
        if (ws == Node.SIGNAL)
            return true;
         前驱节点线程已经被取消了,需要向前找到waitStatus <=0的节点
        if (ws > 0) {
            do {
                node.prev = pred = pred.prev;
            } while (pred.waitStatus > 0);
            pred.next = node;
        } else {
            设置前驱节点线程状态为signal
            pred.compareAndSetWaitStatus(ws, Node.SIGNAL);
        }
        return false;
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值