前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >CountDownLatch讲解-Junit实现多线程测试

CountDownLatch讲解-Junit实现多线程测试

作者头像
胖虎
发布2019-06-26 17:34:13
1.4K0
发布2019-06-26 17:34:13
举报
文章被收录于专栏:晏霖晏霖

你的关注意义重大!

前言

我们知道使用junit进行多线程测试时,主线程执行完毕后直接结束所有线程,(这就好比我前文说线程五种状态中的“STOP”,就是不接受新任务,中断当前正在运行的任务。)导致很多子线程没有执行完呢就已经关闭了,所以为了解决这个问题我们就需要讲解一个JUC又一个重要的类CountDownLatch,使用AQS状态表示计数,可以把它看成是一个计数器,源码注释第一句话:A synchronization aid that allows one or more threads to wait until,翻译过来就是:允许一个或多个线程等待。好,让我们揭开CountDownLatch的面纱,并用它解决junit多线程问题。

正文

胖虎带领大家阅读一下CountDownLatch类的部分源码,当然我不会把源码将一个遍,只会说一些重要的内容,不过大家不要慌,CountDownLatch中一共就312行代码,80%是注释,哈哈。

首先CountDownLatch类中官方的解释是:

允许一个或多个线程等待,在其他线程中执行的一组操作完成。用给定的<em>count</em>初始化。方法块{@link#await await}直到当前计数达到由于调用{@link#countDown}方法而为零,之后释放所有等待的线程以及随后的任何调用。

让我们三步走,介绍最重要的三个方法

step1:

该类的构造方法,声明一个CountDownLatch 实例 预定计数次数:5

CountDownLatch countDownLatch = new CountDownLatch(5);

代码语言:javascript
复制
public CountDownLatch(int count) {
   if (count < 0) throw new IllegalArgumentException("count < 0");
   this.sync = new Sync(count);}

step2:

递减锁存器的计数,如果计数到达零,则释放所有等待的线程。 如果当前计数大于零,则将计数减少 1 。

countDownLatch.countDown();

代码语言:javascript
复制
public void countDown() {
       sync.releaseShared(1);
   }

step3:

使当前线程在锁存器倒计数至零之前一直等待,除非线程被中断 , 如果当前的计数为零,则此方法立即返回 。

countDownLatch.await();

代码语言:javascript
复制
public void await() throws InterruptedException {
       sync.acquireSharedInterruptibly(1);
   }

重点的三个方法讲解完毕,其实await()方法还有一个是可以设定等待时常的,我就不贴出来了,是不是觉得很简单。

下面就来让我们使用CountDownLatch在junit多线程环境下保证线程的原子性,说通俗点,就是我创建的所有线程都会执行完毕。

我这个例子是使用的是springboot2.0.2.RELEASE版本自带的junit测试,我这里直接写的是正例,大家拷贝过去可以吧我代码关于countDownLatch对象引用的地方注释掉再运行就是反例,运行结果肯定大于0,因为我五个线程还没运行完就结束了。

代码语言:javascript
复制
import java.util.concurrent.CountDownLatch;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;
import org.junit.Test;
import org.junit.runner.RunWith;import org.springframework.boot.test.context.SpringBootTest;import org.springframework.test.context.junit4.SpringRunner;@RunWith(SpringRunner.class)@SpringBootTest(classes = AppServiceInterfaceApplication.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)public class TeseCase {
   private static Integer count = 10000;
   private CountDownLatch countDownLatch = new CountDownLatch(10000);
   private static final Object obj = new Object();
   @Test    public void test() throws InterruptedException {    
       ExecutorService executorService = Executors.newFixedThreadPool(5);
       for (int i = 1; i <= 10000; i++) {
           try {  
               executorService.execute(() -> {
                   //同步的去做减法
                   synchronized (obj) {
                       count--;
                   }
               });
           } catch (Throwable e) {
               //TODO
           } finally {
               // 很关键, 无论上面程序是否异常必须执行countDown,否则await无法释放
               countDownLatch.countDown();
           }
       }
       // 5个线程countDown()都执行之后才会释放当前线程,程序才能继续往后执行
       countDownLatch.await();
       //关闭线程池
       executorService.shutdown();
       System.out.println(count);
       System.out.println(Thread.currentThread().getName() + ":这是最后一个线程!");
   }}

运行结果:

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2018-12-27,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 晏霖 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档