美文网首页Java高级进阶
CountDownLatch和CyclicBarrier模拟同时

CountDownLatch和CyclicBarrier模拟同时

作者: e4e9aa34f536 | 来源:发表于2018-10-29 15:47 被阅读1次

    有时候要测试一下某个功能的并发能力,又不要想借助于其他测试工具,索性就自己写简单的demo模拟一个并发请求就最方便了。如果熟悉jemter的测试某接口的并发能力其实更专业,此处只是自己折腾着玩。

    CountDownLatch和CyclicBarrier是jdk concurrent包下非常有用的两个并发工具类,它们提供了一种控制并发流程的手段。其实查看源码它们都是在内部维护了一个计数器控制流程的

    CountDownLatch:一个或者多个线程,等待其他多个线程完成某件事情之后才能执行;

    CyclicBarrier:多个线程互相等待,直到到达同一个同步点,再继续一起执行。

    CountDownLatch和CyclicBarrier的区别

    CountDownLatch的计数器,线程完成一个记录一个,计数器是递减 计数器,只能使用一次

    CyclicBarrier的计数器 更像是一个阀门,需要所有线程都到达,阀门才能打开,然后继续执行,计数器是递增 计数器提供reset功能,可以多次使用

    另外Semaphore可以控同时访问的线程个数,通过 acquire() 获取一个许可,如果没有就等待,而 release() 释放一个许可。

    通常我们模拟并发请求,一般都是多开几个线程,发起请求就好了。但是方式,一般会存在启动的先后顺序了,算不得真正的同时并发!怎么样才能做到真正的同时并发呢?是本文想说的点,java中提供了闭锁 CountDownLatch, CyclicBarrier 刚好就用来做这种事就最合适了。

    下面分别使用CountDownLatch和CyclicBarrier来模拟并发的请求

    CountDownLatch模拟

    packagecom.test;importjava.io.BufferedReader;importjava.io.IOException;importjava.io.InputStream;importjava.io.InputStreamReader;importjava.io.OutputStream;importjava.net.HttpURLConnection;importjava.net.MalformedURLException;importjava.net.URL;importjava.util.concurrent.CountDownLatch;publicclassLatchTest{publicstaticvoidmain(String[] args)throwsInterruptedException{ Runnable taskTemp =newRunnable() {// 注意,此处是非线程安全的,留坑privateintiCounter;@Overridepublicvoidrun(){for(inti =0; i <10; i++) {// 发起请求// HttpClientOp.doGet("https://www.baidu.com/");iCounter++; System.out.println(System.nanoTime() +" ["+ Thread.currentThread().getName() +"] iCounter = "+ iCounter);try{ Thread.sleep(100); }catch(InterruptedException e) { e.printStackTrace(); } } } }; LatchTest latchTest =newLatchTest(); latchTest.startTaskAllInOnce(5, taskTemp); }publiclongstartTaskAllInOnce(intthreadNums,finalRunnable task)throwsInterruptedException{finalCountDownLatch startGate =newCountDownLatch(1);finalCountDownLatch endGate =newCountDownLatch(threadNums);for(inti =0; i < threadNums; i++) { Thread t =newThread() {publicvoidrun(){try{// 使线程在此等待,当开始门打开时,一起涌入门中startGate.await();try{ task.run(); }finally{// 将结束门减1,减到0时,就可以开启结束门了endGate.countDown(); } }catch(InterruptedException ie) { ie.printStackTrace(); } } }; t.start(); }longstartTime = System.nanoTime(); System.out.println(startTime +" ["+ Thread.currentThread() +"] All thread is ready, concurrent going...");// 因开启门只需一个开关,所以立马就开启开始门startGate.countDown();// 等等结束门开启endGate.await();longendTime = System.nanoTime(); System.out.println(endTime +" ["+ Thread.currentThread() +"] All thread is completed.");returnendTime - startTime; }}

    执行结果

    CyclicBarrier模拟

    // 与 闭锁 结构一致publicclassLatchTest{publicstaticvoidmain(String[] args)throwsInterruptedException{  Runnable taskTemp =newRunnable() {privateintiCounter;@Overridepublicvoidrun(){// 发起请求// HttpClientOp.doGet("https://www.baidu.com/");iCounter++; System.out.println(System.nanoTime() +" ["+ Thread.currentThread().getName() +"] iCounter = "+ iCounter); } }; LatchTest latchTest =newLatchTest();// latchTest.startTaskAllInOnce(5, taskTemp);latchTest.startNThreadsByBarrier(5, taskTemp); }publicvoidstartNThreadsByBarrier(intthreadNums, Runnable finishTask)throwsInterruptedException{// 设置栅栏解除时的动作,比如初始化某些值CyclicBarrier barrier =newCyclicBarrier(threadNums, finishTask);// 启动 n 个线程,与栅栏阀值一致,即当线程准备数达到要求时,栅栏刚好开启,从而达到统一控制效果for(inti =0; i < threadNums; i++) { Thread.sleep(100);newThread(newCounterTask(barrier)).start(); } System.out.println(Thread.currentThread().getName() +" out over..."); }}classCounterTaskimplementsRunnable{// 传入栅栏,一般考虑更优雅方式privateCyclicBarrier barrier;publicCounterTask(finalCyclicBarrier barrier){this.barrier = barrier; }publicvoidrun(){ System.out.println(Thread.currentThread().getName() +" - "+ System.currentTimeMillis() +" is ready...");try{// 设置栅栏,使在此等待,到达位置的线程达到要求即可开启大门barrier.await(); }catch(InterruptedException e) { e.printStackTrace(); }catch(BrokenBarrierException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() +" - "+ System.currentTimeMillis() +" started..."); }}

    执行结果

    并发请求操作流程示意图如下:

    此处设置了一道门,以保证所有线程可以同时生效。但是,此处的同时启动,也只是语言层面的东西,也并非绝对的同时并发。具体的调用还要依赖于CPU个数,线程数及操作系统的线程调度功能等,不过咱们也无需纠结于这些了,重点在于理解原理!

    毕竟测试并发 还得用专业的工具 jmeter 还是很方便的.

    欢迎工作一到八年的Java工程师朋友们加入Java高级交流群:854630135

    本群提供免费的学习指导 架构资料 以及免费的解答

    不懂得问题都可以在本群提出来 之后还会有直播平台和讲师直接交流噢

    哦对了,喜欢就别忘了关注一下哦~

    相关文章

      网友评论

        本文标题:CountDownLatch和CyclicBarrier模拟同时

        本文链接:https://www.haomeiwen.com/subject/vewbtqtx.html