原创声明:本文来源于公众号【胖滚猪学编程】,转载请注明出处。

上一节【漫画】JAVA并发编程三大Bug源头(可见性、原子性、有序性)我们聊了聊并发编程的三个bug源头,这还没开始进入并发世界,胖滚猪就遇到了难题。。

这个难题是所有初学者都会有的疑惑:没法复现那些理论知识告诉我们的bug。但是实际操练很重要,那么在本地开发环境,到底应该怎样模拟并发呢?

模拟并发工具大全

在本地模拟并发环境的方法有挺多的,比较热门的有以下几种,包括工具和代码:

1、Postman:Http请求模拟工具,可以设置发起N个请求(但不推荐,并不专业)

2、Apache Bench(AB):Apache 服务器的一个web压力测试工具,是一个命令行工具,可根据命令创建很多并发访问线程,模拟多个访问者同时对某一个URL地址进行访问。总体来说,ab工具小巧简单,上手学习较快,可以提供需要的基本性能指标;但是缺点就是没有图形化结果,不能监控。

3、Apache JMeter:Apache组织开发的基于Java的压力测试工具。功能相比AB会更加强大,尤其是有GUI图形化界面,这一点很爽。另外jmeter是一次完整的请求和返回;AB只是发出去请求,并不对返回做处理。如果你希望看到返回结果,那么也应该选择JMeter。

4、JAVA代码:包括CountDownLatch、CyclicBarrier等

我们主要说一下如何通过jmeter和代码来模拟并发环境,也推荐使用这两种方式。

CountDownLatch(等待多线程完成)

原创声明:本文来源于公众号【胖滚猪学编程】,转载请注明出处。

countDownLatch是在java1.5被引入,存在于java.util.cucurrent包下。

这个类能使一个线程等待其他线程各自执行完毕后再执行

它是通过一个计数器来实现的,计数器的初始值是线程的数量。每当一个线程执行完毕后,计数器的值就-1,当计数器的值为0时,表示所有线程都执行完毕,然后在闭锁上等待的线程就可以恢复工作了。

如图所示,初始值cnt=3,线程A执行了await方法所以被阻塞等待,T1\T2\T3线程通过调用countDown,让计数器减一,直到cnt=0后,Thread A才恢复运行。换句话说就是,Thread A需要等待其他三个线程都执行完才能执行:

countDownLatch类中只提供了一个构造器:

//参数count为计数值
public CountDownLatch(int count) { };
countDownLatch类中有三个方法是最重要的:

//调用await()方法的线程会被挂起,它会等待直到count值为0才继续执行

public void await() throws InterruptedException { };
//和await()类似,只不过等待一定的时间后count值还没变为0的话就会继续执行
public boolean await(long timeout, TimeUnit unit) throws InterruptedException { };
//将count值减1
public void countDown() { };

举例:需求是处理一个Excel,Excel有很多行数据,为了效率,我们可以使用多线程处理,但是处理完所有行数据后,需要通知到主线程。如果没有countDownLatch,那么效果是这样的,还没处理完呢你就说我结束了:

如果在主线程上加上countDownLatch,并且调用await()方法,那么主线程会被挂起,它会等待直到count值为0才继续执行:

    static CountDownLatch countDownLatch = new CountDownLatch(100);

    public static void main(String[] args) throws InterruptedException {
for (int i = 0; i < 100; i++) {
Thread thread = new Thread(() -> {
doWork();
countDownLatch.countDown();
});
thread.start(); }
countDownLatch.await();
System.out.println("处理完整个excel的结束时间"+System.currentTimeMillis());
} public static void doWork(){
System.out.println("处理行数据,时间"+System.currentTimeMillis());
}

Thread thread = new Thread(() -> {
try {
countDownLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
doWork();
});
thread.start();
countDownLatch.countDown();

线程池

 ExecutorService executorService = new ThreadPoolExecutor(100,
200, 60, TimeUnit.MINUTES, new ArrayBlockingQueue<Runnable>(20000), new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
return new Thread(r);
}
});

CyclicBarrier(同步屏障)

原创声明:本文来源于公众号【胖滚猪学编程】,转载请注明出处。

CyclicBarrier 的字面意思是可循环使用(Cyclic)的屏障(Barrier)。它要做的事情是,让一组线程到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程才会继续干活。

如下图所示,一共4个线程A、B、C、D,它们到达屏障的顺序可能各不相同。当A、B、C到达栅栏后,由于没有满足总数【4】的要求,所以会一直等待,当线程D到达后,栅栏才会放行。

CyclicBarrier构造方法

//其参数表示屏障拦截的线程数量
public CyclicBarrier(int parties)
//多了回调函数
public CyclicBarrier(int parties, Runnable barrierAction)

主要方法如下

//调用await方法的线程告诉CyclicBarrier自己已经到达同步点,然后当前线程被阻塞。直到parties个参与线程调用了await方法,阻塞线程才会执行。
public int await()
//带超时时间参数
public int await(long timeout, TimeUnit unit)
//重置
public void reset()

根据这一特性,我们也可以用于并发模拟,如下代码就是模拟了5个线程并发执行:

  private static CyclicBarrier cyclicBarrier = new CyclicBarrier(5);

  public static void main(String[] args) throws InterruptedException {
ExecutorService executorService = ExecutorServiceUtils.getExecutor();
for (int i = 0; i < 20; i++) {
int finalI = i;
Thread.sleep(1000);
executorService.submit(() -> {
try {
doWork(finalI);
} catch (Exception e) {
e.printStackTrace();
}
});
//通过打印日志 得出它具有自动重置功能
log.info("Parties={} 等待中{}",cyclicBarrier.getParties(),cyclicBarrier.getNumberWaiting());
}
executorService.shutdown();
} public static void doWork(Integer threadNum) throws Exception {
Thread.sleep(1000);
log.info("{} is ready", threadNum);
cyclicBarrier.await();
log.info("{} continue", threadNum);
}

CountDownLatch 和 CyclicBarrier 的主要区别:

1、CountDownLatch 主要用来解决一个线程等待多个线程的场景,可以类比旅游团团长要等待所有的游客到齐才能去下一个景点;

而CyclicBarrier 是一组线程之间互相等待,更像是几个驴友之间不离不弃。

2、CountDownLatch是减计数方式,而CyclicBarrier是加计数方式。

3、CountDownLatch 的计数器是不能循环利用的,也就是说一旦计数器减到 0,再有线程调用 await(),该线程会直接通过。

但CyclicBarrier 的计数器是可以循环利用的,而且具备自动重置的功能,一旦计数器减到 0 会自动重置到你设置的初始值。

4、除此之外,CyclicBarrier 还可以设置回调函数,可以说是功能丰富。而CountDownLatch不支持回调函数。

好了,现在再回到最开头那段无法复现的代码,我们用CyclicBarrier来改写一下,你就可以看到出现0的情况了。

另外还要说一点:即使是真正的并发执行了,出问题依旧是小概率事件,本人亲测运行了15次才出现0的结果。运气不好可能运行100次还是不会看到。不必太过于纠结这些哦!

JMeter工具

1、下载好后解压目录,配置环境变量,运行jmeter.bat即可

2、添加一个线程组:

3、配置线程组相关属性,主要是线程数量以及是否循环,这里我们设置并发线程数是50,执行完每个线程后不需要循环:

4、添加http请求,比如我们要测试/test接口的请求:

配置http ip\端口\编码格式等:

5、添加两个监听器、用于执行结束后查看图形结果和查看结果数:

6、运行线程组,就可以输出我们的结果了

好了,今天就到这里了,又到了要跟大家说拜拜的时候了~

原创声明:本文来源于公众号【胖滚猪学编程】,转载请注明出处。

本文转载自公众号【胖滚猪学编程】 用漫画让编程so easy and interesting!欢迎关注!形象来源于微信表情包【胖滚家族】喜欢可以下载哦~

【漫画】JAVA并发编程之并发模拟工具的更多相关文章

  1. Java并发编程系列-(2) 线程的并发工具类

    2.线程的并发工具类 2.1 Fork-Join JDK 7中引入了fork-join框架,专门来解决计算密集型的任务.可以将一个大任务,拆分成若干个小任务,如下图所示: Fork-Join框架利用了 ...

  2. java并发编程笔记(二)——并发工具

    java并发编程笔记(二)--并发工具 工具: Postman:http请求模拟工具 Apache Bench(AB):Apache附带的工具,测试网站性能 JMeter:Apache组织开发的压力测 ...

  3. java并发编程系列原理篇--JDK中的通信工具类Semaphore

    前言 java多线程之间进行通信时,JDK主要提供了以下几种通信工具类.主要有Semaphore.CountDownLatch.CyclicBarrier.exchanger.Phaser这几个通讯类 ...

  4. java并发编程工具类JUC第四篇:LinkedBlockingQueue链表队列

    在之前的文章中已经为大家介绍了java并发编程的工具:BlockingQueue接口.ArrayBlockingQueue.DelayQueue. LinkedBlockingQueue 队列是Blo ...

  5. java并发编程工具类JUC第七篇:BlockingDeque双端阻塞队列

    在之前的文章中已经为大家介绍了java并发编程的工具:BlockingQueue接口.ArrayBlockingQueue.DelayQueue.LinkedBlockingQueue.Priorit ...

  6. java并发编程工具类JUC第八篇:ConcurrentHashMap

    在之前的文章中已经为大家介绍了java并发编程的工具:BlockingQueue接口.ArrayBlockingQueue.DelayQueue.LinkedBlockingQueue.Priorit ...

  7. Java并发编程工具类 CountDownLatch CyclicBarrier Semaphore使用Demo

    Java并发编程工具类 CountDownLatch CyclicBarrier Semaphore使用Demo CountDownLatch countDownLatch这个类使一个线程等待其他线程 ...

  8. 【Java并发编程实战】-----“J.U.C”:CountDownlatch

    上篇博文([Java并发编程实战]-----"J.U.C":CyclicBarrier)LZ介绍了CyclicBarrier.CyclicBarrier所描述的是"允许一 ...

  9. JAVA并发编程J.U.C学习总结

    前言 学习了一段时间J.U.C,打算做个小结,个人感觉总结还是非常重要,要不然总感觉知识点零零散散的. 有错误也欢迎指正,大家共同进步: 另外,转载请注明链接,写篇文章不容易啊,http://www. ...

随机推荐

  1. Xshell远程连接Linux系统

    一般来说我们连接Linux,会使用到一些远程连接工具 比如:Xshell和Xftp Xshell:远程连接linux系统 Xftp:远程在Linux系统中上传或下载文件 Xshell和Xftp百度云链 ...

  2. C#集合类型——Hashtable、Dictionary之浅谈

    Hashtable表 数组.数组集合.List集合都是通过索引来访问里面成员.哈希表则是通过键来访问成员值.键不可为空,值可为空. 比如: Hashtable  hash=new  Hashtable ...

  3. Python修改paramiko模块开发运维审计保垒机

    目前市面上,专门做IT审计堡垒机的厂商有很多,他们的产品都有一个特点,那就是基本上每台的售价都在20万以上.像我们做技术的,不可能每次待的公司都是大公司,那么在小公司,是不太可能投资20多万买一台硬件 ...

  4. 高德局部刷新标记点,bug解决

    将接口返回的经纬集合点在高德地图上标记展示, 如果实时刷新地图标记点,不加优化,则会造成过多的带宽消耗 所以,地图只需加载一次,局部更新标记点就好了 代码: <template> < ...

  5. PHP中静态(static)调用非静态方法详解--调用!!!

    来源:https://www.cnblogs.com/yolo-bean/p/7739265.html 这里分析了php面向对象中static静态属性和静态方法的调用.关于它们的调用(能不能调用,怎么 ...

  6. php 全局变量和超全局变量

    global 全局变量(在当前页面全部地方有效) $GLOBALS['name'] 超全局变量(在整个网站全部地方有效) 一个包含了全部变量的全局组合数组.变量的名字就是数组的键.还有_GET,_PO ...

  7. HDU 1402 A*B

    #include <bits/stdc++.h> using namespace std; typedef long long ll; #define ms(s,a) memset(s,a ...

  8. mac OS git关联github

    正在更新 mac OS 默认安装了git  git -v 查看版本 mac OS 默认安装了ssh  ssh -v 查看版本 1.设置username和email(github每次commit都会记录 ...

  9. element-ui中cascader同时获取label和value值

    关于elementUI中cascader选中值后,能获取value或者label,但不能同时获value和label,这一问题,琢磨出了这么个办法.以新增和编辑城市为例,type: 1 编辑,type ...

  10. Kudu,支持快速分析的新型Hadoop存储系统

    Kudu是Cloudera开源的新型列式存储系统,是Apache Hadoop生态圈的新成员之一(incubating),专门为了对快速变化的数据进行快速的分析,填补了以往Hadoop存储层的空缺.本 ...