CountDownLatch并发工具类(二)

  • Post author:
  • Post category:其他




CountDownLatch



1. countDownLatch 简介

CountDownLatch是一个同步工具类,它允许一个或多个线程一直等待,直到其他countDownLatch中的线程里执行完后再执行其他等待的线程。

  • 举例:要求主线程等待10个同样步骤的线程执行完后,主线程才继续执行下面的任务。任务开始时,就需要将10个线程放入计数器countDownLatch中,主线程等待,直到10个线程中每一个线程都执行完后,主线程才开始继续执行,在这个过程中,10个线程相互间可以不必等待,来一个就执行一个,直到计数器计算到有10个线程都执行完即可。



2.countDownLatch 的原理

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

  • await用来等待,countDown负责计数器的减1;
  • counDownLatch是一个一次性的, 计数无法重置。若需要一个重置的版本计数,考虑使用CyclicBarrier(下一篇文章介绍)。



结构图

在这里插入图片描述

上图,我们可以看到countDownLatch的主要方法,接下来为大家介绍主要使用的几个方法:



2.1 await()

函数将会使当前线程在锁存器倒计数至零之前一直等待,除非线程被中断。其源码如下:

    public void await() throws InterruptedException {
        sync.acquireSharedInterruptibly(1);
    }
 
   //-----------------------------------------------------------
 
    public final void acquireSharedInterruptibly(int arg)
            throws InterruptedException {
        if (Thread.interrupted())
            throw new InterruptedException();
        //这里可以看到 最终调用的是Sync中的 tryAcquireShared 方法 
        // return (count == 0) ? 1 : -1;
        if (tryAcquireShared(arg) < 0)
            doAcquireSharedInterruptibly(arg);
    }
 
 
//-------------------------------------------------------
 
 
    public boolean await(long timeout, TimeUnit unit)
        throws InterruptedException {
        return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout));
    }



2.2 .countDown()

此函数将递减(减一)锁存器的计数,如果计数到达零,则释放所有等待的线程

   /**   
     * count值减 1,直到计数达到零,释放所有等待的线程 。
     *      
     *  <p>如果当前计数大于零,则递减。
     *   如果新计数为零,则重新启用所有等待的线程 ,达到线程调度的目的。
     *      
     * <p>如果当前计数等于零,则没有任何反应。
     */
    public void countDown() {
        sync.releaseShared(1);
    }
 
//-------------------------------------------------------------------------
   /**
     * 此函数会以共享模式释放对象,
     * 并且在函数中会调用到CountDownLatch的tryReleaseShared函数,
     * 当且仅当新计数返回0时,会调用AQS的doReleaseShared函数, 
     */
    public final boolean releaseShared(int arg) {
        if (tryReleaseShared(arg)) {
            doReleaseShared();
            return true;
        }
        return false;
    }



3.实例

初始化计数器要有6个线程执行完后,扣除完毕以后,主线程和业务线程才能继续自己的工作

代码如下:

public class UseCountDownLatch {
	
	static CountDownLatch latch = new CountDownLatch(6);

	//初始化线程(只有一步,有4个)
    private static class InitThread implements Runnable{

        @Override
        public void run() {
        	System.out.println("Thread_"+Thread.currentThread().getId()
        			+" ready init work......");
        	latch.countDown();//初始化线程完成工作了,countDown方法只扣减一次;
            for(int i =0;i<2;i++) {
            	System.out.println("Thread_"+Thread.currentThread().getId()
            			+" ........continue do its work");
            }
        }
    }
    
    //业务线程
    private static class BusiThread implements Runnable{

        @Override
        public void run() {
        	try {
				latch.await();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
            for(int i =0;i<3;i++) {
            	System.out.println("BusiThread_"+Thread.currentThread().getId()
            			+" do business-----");
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {
    	//单独的初始化线程,初始化分为2步,需要扣减两次
        new Thread(new Runnable() {
            @Override
            public void run() {
            	SleepTools.ms(1);
                System.out.println("Thread_"+Thread.currentThread().getId()
            			+" ready init work step 1st......");
                latch.countDown();//每完成一步初始化工作,扣减一次
                System.out.println("begin step 2nd.......");
                SleepTools.ms(1);
                System.out.println("Thread_"+Thread.currentThread().getId()
            			+" ready init work step 2nd......");
                latch.countDown();//每完成一步初始化工作,扣减一次
            }
        }).start();
        new Thread(new BusiThread()).start();
        for(int i=0;i<=3;i++){
            Thread thread = new Thread(new InitThread());
            thread.start();
        }

        latch.await();
        System.out.println("Main do ites work........");
    }
}

运行结果如下:

Thread_13 ready init work......
Thread_13 ........continue do its work
Thread_13 ........continue do its work
Thread_14 ready init work......
Thread_14 ........continue do its work
Thread_14 ........continue do its work
Thread_15 ready init work......
Thread_15 ........continue do its work
Thread_15 ........continue do its work
Thread_11 ready init work step 1st......
begin step 2nd.......
Thread_16 ready init work......
Thread_16 ........continue do its work
Thread_16 ........continue do its work
Thread_11 ready init work step 2nd......
Main do ites work........
BusiThread_12 do business-----
BusiThread_12 do business-----
BusiThread_12 do business-----



版权声明:本文为qq_32445069原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。