CountDownLatch和CyclicBarrier模拟同时并发请求

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

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

CountDownLatch:一个或者多个线程,等待其他多个线程完成某件事情之后才能执行;
CyclicBarrier:多个线程互相等待,直到到达同一个同步点,再继续一起执行。
CountDownLatch和CyclicBarrier的区别
CountDownLatch的计数器,线程完成一个记录一个,计数器是递减 计数器,只能使用一次
CyclicBarrier的计数器 更像是一个阀门,需要所有线程都到达,阀门才能打开,然后继续执行,计数器是递增 计数器提供reset功能,可以多次使用
另外Semaphore可以控同时访问的线程个数,通过 acquire() 获取一个许可,如果没有就等待,而 release() 释放一个许可。

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

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

package com.test;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.concurrent.CountDownLatch;
public class LatchTest {
 public static void main(String[] args) throws InterruptedException {
 Runnable taskTemp = new Runnable() {
       // 注意,此处是非线程安全的,留坑
 private int iCounter;
 @Override
 public void run() {
 for(int i = 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 = new LatchTest();
 latchTest.startTaskAllInOnce(5, taskTemp);
 }
 public long startTaskAllInOnce(int threadNums, final Runnable task) throws InterruptedException {
 final CountDownLatch startGate = new CountDownLatch(1);
 final CountDownLatch endGate = new CountDownLatch(threadNums);
 for(int i = 0; i < threadNums; i++) {
 Thread t = new Thread() {
 public void run() {
 try {
 // 使线程在此等待,当开始门打开时,一起涌入门中
 startGate.await();
 try {
 task.run();
 } finally {
 // 将结束门减1,减到0时,就可以开启结束门了
 endGate.countDown();
 }
 } catch (InterruptedException ie) {
 ie.printStackTrace();
 }
 }
 };
 t.start();
 }
 long startTime = System.nanoTime();
 System.out.println(startTime + " [" + Thread.currentThread() + "] All thread is ready, concurrent going...");
 // 因开启门只需一个开关,所以立马就开启开始门
 startGate.countDown();
 // 等等结束门开启
 endGate.await();
 long endTime = System.nanoTime();
 System.out.println(endTime + " [" + Thread.currentThread() + "] All thread is completed.");
 return endTime - startTime;
 }
}

执行结果

CyclicBarrier模拟

// 与 闭锁 结构一致
public class LatchTest {
 public static void main(String[] args) throws InterruptedException {

 Runnable taskTemp = new Runnable() {
 private int iCounter;
 @Override
 public void run() {
 // 发起请求
// HttpClientOp.doGet("https://www.baidu.com/");
 iCounter++;
 System.out.println(System.nanoTime() + " [" + Thread.currentThread().getName() + "] iCounter = " + iCounter);
 }
 };
 LatchTest latchTest = new LatchTest();
// latchTest.startTaskAllInOnce(5, taskTemp);
 latchTest.startNThreadsByBarrier(5, taskTemp);
 }
 public void startNThreadsByBarrier(int threadNums, Runnable finishTask) throws InterruptedException {
 // 设置栅栏解除时的动作,比如初始化某些值
 CyclicBarrier barrier = new CyclicBarrier(threadNums, finishTask);
 // 启动 n 个线程,与栅栏阀值一致,即当线程准备数达到要求时,栅栏刚好开启,从而达到统一控制效果
 for (int i = 0; i < threadNums; i++) {
 Thread.sleep(100);
 new Thread(new CounterTask(barrier)).start();
 }
 System.out.println(Thread.currentThread().getName() + " out over...");
 }
}
class CounterTask implements Runnable {
 // 传入栅栏,一般考虑更优雅方式
 private CyclicBarrier barrier;
 public CounterTask(final CyclicBarrier barrier) {
 this.barrier = barrier;
 }
 public void run() {
 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 还是很方便的.

原文地址:http://blog.51cto.com/13954634/2310317

时间: 2024-08-23 15:28:11

CountDownLatch和CyclicBarrier模拟同时并发请求的相关文章

使用Java辅助类(CountDownLatch、CyclicBarrier、Semaphore)并发编程

在java 1.5中,提供了一些非常有用的辅助类来帮助我们进行并发编程,比如CountDownLatch,CyclicBarrier和Semaphore,今天我们就来学习一下这三个辅助类的用法 一.CountDownLatch用法 CountDownLatch类位于java.util.concurrent包下,利用它可以实现类似计数器的功能.比如有一个任务A,它要等待其他4个任务执行完毕之后才能执行,此时就可以利用CountDownLatch来实现这种功能了. CountDownLatch类只提

Java并发编程:CountDownLatch、CyclicBarrier和Semaphore

在java 1.5中,提供了一些非常有用的辅助类来帮助我们进行并发编程,比如CountDownLatch,CyclicBarrier和Semaphore,今天我们就来学习一下这三个辅助类的用法. 以下是本文目录大纲: 一.CountDownLatch用法 二.CyclicBarrier用法 三.Semaphore用法 若有不正之处请多多谅解,并欢迎批评指正. 请尊重作者劳动成果,转载请标明原文链接: http://www.cnblogs.com/dolphin0520/p/3920397.htm

使用CountDownLatch和CyclicBarrier处理并发线程

闲话不说,首先看一段代码: { IValueCallback remoteCallback = new IValueCallback.Stub() { <strong><span style="color:#ff0000;">(B)</span></strong> public void onReceiveValue(final Bundle value) throws RemoteException { synchronized (sy

用CountDownLatch和CyclicBarrier处理并发线程

闲话不说,先来看一段代码: { IValueCallback remoteCallback = new IValueCallback.Stub() { <strong><span style="color:#ff0000;">(B)</span></strong> public void onReceiveValue(final Bundle value) throws RemoteException { synchronized (sy

Java并发编程:CountDownLatch、CyclicBarrier和 Semaphore

在java 1.5中,提供了一些非常有用的辅助类来帮助我们进行并发编程,比如CountDownLatch,CyclicBarrier和Semaphore,今天我们就来学习一下这三个辅助类的用法. 以下是本文目录大纲: 一.CountDownLatch用法 二.CyclicBarrier用法 三.Semaphore用法 一.CountDownLatch用法 CountDownLatch类位于java.util.concurrent包下,利用它可以实现类似计数器的功能.比如有一个任务A,它要等待其他

并发编程(七)——AbstractQueuedSynchronizer 之 CountDownLatch、CyclicBarrier、Semaphore 源码分析

这篇,我们的关注点是 AQS 最后的部分,共享模式的使用.本文先用 CountDownLatch 将共享模式说清楚,然后顺着把其他 AQS 相关的类 CyclicBarrier.Semaphore 的源码一起过一下. CountDownLatch CountDownLatch 这个类是比较典型的 AQS 的共享模式的使用,这是一个高频使用的类.使用方法在前面一篇文章中有介绍 并发编程(二)—— CountDownLatch.CyclicBarrier和Semaphore 使用例子 我们看下 Do

25.大白话说java并发工具类-CountDownLatch,CyclicBarrier,Semaphore,Exchanger

1. 倒计时器CountDownLatch 在多线程协作完成业务功能时,有时候需要等待其他多个线程完成任务之后,主线程才能继续往下执行业务功能,在这种的业务场景下,通常可以使用Thread类的join方法,让主线程等待被join的线程执行完之后,主线程才能继续往下执行.当然,使用线程间消息通信机制也可以完成.其实,java并发工具类中为我们提供了类似"倒计时"这样的工具类,可以十分方便的完成所说的这种业务场景. 为了能够理解CountDownLatch,举一个很通俗的例子,运动员进行跑

java并发编程之CountDownLatch与CyclicBarrier

CountDownLatch和CyclicBarrier是jdk concurrent包下非常有用的两个并发工具类,它们提供了一种控制并发流程的手段.本文将会提供一些应用场景,结合源码,对它们的具体实现以及如何使用做一个具体分析. CountDownLatch CountDownLatch允许一个或多个线程等待其他线程完成操作. CountDownLatch使用案例 需求:解析一个文件下多个txt文件数据,可以考虑使用多线程并行解析以提高解析效率.每一个线程解析一个文件里的数据,等到所有数据解析

并发工具类:CountDownLatch、CyclicBarrier、Semaphore

在多线程的场景下,有些并发流程需要人为来控制,在JDK的并发包里提供了几个并发工具类:CountDownLatch.CyclicBarrier.Semaphore. 一.CountDownLatch 1 import java.util.concurrent.CountDownLatch; 2 3 4 public class CountDownLatchTest 5 { //设置N为2 6 static CountDownLatch c = new CountDownLatch(2); 7 p