多线程学习笔记-CountDownLatch

CountDownLatch介绍

CountDownLatch是一个同步工具类,它允许一个或多个线程一直等待,直到其他线程执行完后再执行。
CountDownLatch是在java1.5被引入的,跟它一起被引入的并发工具类还有CyclicBarrier、Semaphore、ConcurrentHashMap和BlockingQueue,它们都存在于java.util.concurrent包下

CountDownLatch原理

CountDownLatch是通过一个计数器来实现的,计数器的初始化值为线程的数量。每当一个线程完成了自己的任务后,计数器的值就相应得减1。当计数器到达0时,表示所有的线程都已完成任务,然后在闭锁上等待的线程就可以恢复执行任务。

/**
 * 串行的步骤,中间有些步骤可以并行处理,提高效率。就可以使用CountDownLatch
 */
public class CountDownLatchExample {
  private static Random random = new Random(System.currentTimeMillis());

  private static ExecutorService executor = Executors.newFixedThreadPool(2);

  private final static CountDownLatch latch = new CountDownLatch(10);

  public static void main(String[] args) throws InterruptedException{
    //1.
    int[] data = query();
    //2.
    for(int i=0;i<data.length;i++){
      executor.execute(new SimpleRunnable(data,i,latch));
    }
    //3.
    latch.await();
    System.out.println("all of work finish done");
    executor.shutdown();
//    executor.awaitTermination(1, TimeUnit.HOURS);

  }
  static class SimpleRunnable implements Runnable{

    private final int[] data;

    private final int index;

    private final CountDownLatch latch;

    public SimpleRunnable(int[] data,int index, CountDownLatch latch) {
      this.data = data;
      this.index = index;
      this.latch = latch;
    }

    @Override
    public void run() {
      try {
        Thread.sleep(random.nextInt(2000));
      } catch (InterruptedException e) {
        e.printStackTrace();
      }

      int value = data[index];
      if (value%2==0) {
        data[index] = value*2;
      } else{
        data[index] = value *10;
      }
      System.out.println(Thread.currentThread().getName()+" finish");
      latch.countDown();
      System.out.println(latch.getCount());
    }
  }
  private static int[] query(){
    return new int[]{1,2,3,4,5,6,7,8,9,10};
  }
}

在这里插入图片描述
源码解析

构造CountDownLatch传入的计数器实际为Sync中state的值

    public CountDownLatch(int count) {
        if (count < 0) throw new IllegalArgumentException("count < 0");
        // count实际为同步器中state
        this.sync = new Sync(count);
    }

CountDownLatch内部类Sync继承自AbstractQueuedSynchronizer

        Sync(int count) {
            setState(count);
        }

await方法调用链

CountDownLatch#await方法

    public void await() throws InterruptedException {
        sync.acquireSharedInterruptibly(1);
    }

AbstractQueuedSynchronizer#acquireSharedInterruptibly方法

    public final void acquireSharedInterruptibly(int arg)
            throws InterruptedException {
        if (Thread.interrupted())
            throw new InterruptedException();
        if (tryAcquireShared(arg) < 0)
            doAcquireSharedInterruptibly(arg);
    }

CountDownLatch#Sync#tryAcquireShared方法

        protected int tryAcquireShared(int acquires) {
        	//当计数器=0的时候,返回1
            return (getState() == 0) ? 1 : -1;
        }

AbstractQueuedSynchronizer#doAcquireSharedInterruptibly方法

    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);
        }
    }

上面的例子在main方法中,调用latch.await();,由于刚开始构造的时候,state=10,不等0.条件tryAcquireShared(arg) < 0成立,进入doAcquireSharedInterruptibly方法,由于此方法中退出的唯一条件为r >= 0即state=0,使得main线程在该方法中循环,直到cpu调度,其余10个线程都执行countDown方法,使得state变为0,才能退出循环,从而退出await方法

countDown方法调用链

CountDownLatch#countDown方法

    public void countDown() {
    	// 如果state!=0,直接返回
        sync.releaseShared(1);
    }

AbstractQueuedSynchronizer#releaseShared方法

    public final boolean releaseShared(int arg) {
        if (tryReleaseShared(arg)) {
            doReleaseShared();
            return true;
        }
        return false;
    }

CountDownLatch#Sync#tryReleaseShared方法

        protected boolean tryReleaseShared(int releases) {
            // Decrement count; signal when transition to zero
            for (;;) {
            	// 获取计数器的值
                int c = getState();
                if (c == 0)
                    return false;
                // 计数器-1
                int nextc = c-1;
                //更新state的值
                if (compareAndSetState(c, nextc))
                	//state值为0,返回true
                    return nextc == 0;
            }
        }

上面的例子latch.countDown();除非state=0,否则直接返回,往下执行

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值