并发编程学习笔记之十四并发工具CountDownLatch闭锁

一、CountDownLatch简介

CountDownLatch称为闭锁,其实也是一个计数器,主要用来一个线程等待多个线程工程完成操作,仅执行一次。就像是跟团旅游,导游要等到所有的游客到齐后才会出发前往下一个景点。

示例:CountDownLatch 大小为2,在执行了两次countDown之后,整个才会执行完成,如果CountDownLatch大小为2以上,那么这个将不会正常执行完成,因为有个限制永远不会执行完成。

package cn.com.threadtx.cn.com;

import java.util.concurrent.CountDownLatch;

/**
 * CountDownLatch示例
 */
public class CountDownLatchTest {
     static CountDownLatch c = new CountDownLatch(2);
    public static void main(String[] args) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println(1);
                c.countDown();
                System.out.println(2);
                c.countDown();
            }
        }).start();
        try {
            c.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(3);

    }
}

二、原理分析 

CountDownLatch的实现原理也是基础AQS同步队列器,方法比较少,主要的就是await和countDown。

只有一个含参的构造方法:

    public CountDownLatch(int count) {
        if (count < 0) throw new IllegalArgumentException("count < 0");
        this.sync = new Sync(count);
    }

内部类:Sync继承AbstractQueuedSynchronizer

private static final class Sync extends AbstractQueuedSynchronizer {...}

主要方法: 

//使当前限制在闭锁中倒计数至0之前一直等待,除非线程中断
public void await() throws InterruptedException {...}
//含超时时间
public boolean await(long timeout, TimeUnit unit)throws InterruptedException {...}
//递减闭锁中计数,如果计数到达0,则释放所有等待的线程
public void countDown() {...}
//返回当前计数
public long getCount() {...}
//返回标识此闭锁激起状态的字符串
public String toString() {...}
        

 countDown()方法

    public void countDown() {
        sync.releaseShared(1);//1-1
    }

1-1,调用1-2方法递减计数器,调用1-3方法修改节点状态,唤醒线程

    //1-1
    public final boolean releaseShared(int arg) {
        if (tryReleaseShared(arg)) {//1-2
            doReleaseShared();//1-3
            return true;
        }
        return false;
    }
        //1-2调用内部类方法,如果计数器等于0,直接返回,如果不为空,调用CAS方法修改state的值(每次减1)
        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;
            }
        }
    }
 //1-3修改节点状态,唤醒等待的线程
    private void doReleaseShared() {
        for (;;) {
            Node h = head;
            if (h != null && h != tail) {
                int ws = h.waitStatus;
                if (ws == Node.SIGNAL) {
                    if (!compareAndSetWaitStatus(h, Node.SIGNAL, 0))
                        continue;            // loop to recheck cases
                    unparkSuccessor(h);//@2唤醒线程
                }
                else if (ws == 0 &&
                         !compareAndSetWaitStatus(h, 0, Node.PROPAGATE))
                    continue;                // loop on failed CAS
            }
            if (h == head) //退出循环                  // loop if head changed
                break;
        }
    }

    //@2唤醒线程
     private void unparkSuccessor(Node node) {
        int ws = node.waitStatus;
        if (ws < 0)
            compareAndSetWaitStatus(node, ws, 0);

        Node s = node.next;
        if (s == null || s.waitStatus > 0) {
            s = null;
            //从尾节点遍历找到最渴望被唤醒的线程
            for (Node t = tail; t != null && t != node; t = t.prev)
                if (t.waitStatus <= 0)
                    s = t;
        }
        if (s != null)
            LockSupport.unpark(s.thread);
    }
await()方法:
    public void await() throws InterruptedException {
        sync.acquireSharedInterruptibly(1);//1-1
    }
    //1-1线程中断直接抛错。
     public final void acquireSharedInterruptibly(int arg)
            throws InterruptedException {
        if (Thread.interrupted())
            throw new InterruptedException();
        if (tryAcquireShared(arg) < 0)//1-2
            doAcquireSharedInterruptibly(arg);//1-3
    }
     //1-2判断倒计数器是否已经为0,为0则返回1,不为0返回-1
     protected int tryAcquireShared(int acquires) {
          return (getState() == 0) ? 1 : -1;
     }
     //1-3倒计数器不为,说明还有线程没有到位,需要等待线程,加入到等待队列中
     private void doAcquireSharedInterruptibly(int arg)
        throws InterruptedException {
        final Node node = addWaiter(Node.SHARED);
        boolean failed = true;
        try {
            for (;;) {
                final Node p = node.predecessor();
                if (p == head) {
                    int r = tryAcquireShared(arg);
                    if (r >= 0) {
                        setHeadAndPropagate(node, r);
                        p.next = null; // help GC
                        failed = false;
                        return;
                    }
                }
                if (shouldParkAfterFailedAcquire(p, node) &&
                    parkAndCheckInterrupt())
                    throw new InterruptedException();
            }
        } finally {
            if (failed)
                cancelAcquire(node);
        }
    }

 参考书籍:

方志明 著《Java并发编程艺术》

Doug lea 等著《Java并发编程实战》 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值