Java使用代码模拟高并发操作
Java使用代码模拟高并发操作
为什么80%的码农都做不了架构师?>>>
Java通过代码模拟高并发可以以最快的方式发现我们系统中潜在的线程安全性问题,此处使用Semaphore(信号量)和 CountDownLatch(闭锁)搭配ExecutorService(线程池)来进行模拟,主要介绍如下:
1、Semaphore
JDK 1.5之后会提供这个类
Semaphore是一种基于计数的信号量。它可以设定一个阈值,基于此,多个线程竞争获取许可信号,做完自己的申请后归还,超过阈值后,线程申请许可信号将会被阻塞。Semaphore可以用来构建一些对象池,资源池之类的,比如数据库连接池,我们也可以创建计数为1的Semaphore,将其作为一种类似互斥锁的机制,这也叫二元信号量,表示两种互斥状态。
2、CountDownLatch
JDK 1.5之后会提供这个类,
CountDownLatch这个类能够使一个线程等待其他线程完成各自的工作后再执行。例如,应用程序的主线程希望在负责启动框架服务的线程已经启动所有的框架服务之后再执行。
CountDownLatch是通过一个计数器来实现的,计数器的初始值为线程的数量。每当一个线程完成了自己的任务后,计数器的值就会减1。当计数器值到达0时,它表示所有的线程已经完成了任务,然后在闭锁上等待的线程就可以恢复执行任务。
如下图:
以上两个类可以搭配使用,达到模拟高并发的效果,以下使用代码的形式进行举例:
package modules;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
public class CountExample {
// 请求总数
public static int clientTotal = 5000;
// 同时并发执行的线程数
public static int threadTotal = 200;
public static int count = 0;
public static void main(String[] args) throws Exception {
ExecutorService executorService = Executors.newCachedThreadPool();
//信号量,此处用于控制并发的线程数
final Semaphore semaphore = new Semaphore(threadTotal);
//闭锁,可实现计数器递减
final CountDownLatch countDownLatch = new CountDownLatch(clientTotal);
for (int i = 0; i < clientTotal ; i++) {
executorService.execute(() -> {
try {
//执行此方法用于获取执行许可,当总计未释放的许可数不超过200时,
//允许通行,否则线程阻塞等待,直到获取到许可。
semaphore.acquire();
add();
//释放许可
semaphore.release();
} catch (Exception e) {
//log.error("exception", e);
e.printStackTrace();
}
//闭锁减一
countDownLatch.countDown();
});
}
countDownLatch.await();//线程阻塞,直到闭锁值为0时,阻塞才释放,继续往下执行
executorService.shutdown();
log.info("count:{}", count);
}
private static void add() {
count++;
}
}
如上方法模拟5000次请求,同时最大200个并发操作,观察最后的结果,发现每次的结果都有差别,和预期不符,得出结果部分如下:
22:18:26.449 [main] INFO modules.CountExample - count:4997
22:18:26.449 [main] INFO modules.CountExample - count:5000
22:18:26.449 [main] INFO modules.CountExample - count:4995
22:18:26.449 [main] INFO modules.CountExample - count:4998
最后结论:add 方法 非线程安全
那如何保证add方法 线程安全,将add方法进行如下修改即可:
private static void add() {
count.incrementAndGet();
}
执行结果如下:
22:18:26.449 [main] INFO modules.CountExample - count:5000
22:18:26.449 [main] INFO modules.CountExample - count:5000
22:18:26.449 [main] INFO modules.CountExample - count:5000
22:18:26.449 [main] INFO modules.CountExample - count:5000
22:18:26.449 [main] INFO modules.CountExample - count:5000
22:18:26.449 [main] INFO modules.CountExample - count:5000
22:18:26.449 [main] INFO modules.CountExample - count:5000
22:18:26.449 [main] INFO modules.CountExample - count:5000
最后结论:修改后 的 add 方法 线程安全
转载于:https://my.oschina.net/ruoli/blog/1801866
Java使用代码模拟高并发操作相关教程
使用Cacti监控你的网络(五)- Cacti插件
使用Cacti监控你的网络(五)- Cacti插件 一、 概述及Cacti的工作流程 二、 Cacti的安装 三、 Cacti的使用 四、 Cacti脚本及模板 五、 Cacti插件 六、 Cacti高级应用--打造自己的Cacti模板 一、 Cacti 插件 Cacti插件是对cacti的扩展。要使用cacti插件必须先
使用Cacti监控你的网络(三)- Cacti的使用
使用Cacti监控你的网络(三)- Cacti的使用 一、 概述及Cacti的工作流程 二、 Cacti的安装 三、 Cacti的使用 四、 Cacti脚本及模板 五、 Cacti插件 六、 Cacti高级应用--打造自己的Cacti模板 一、Cacti的使用 1.界面介绍登陆Cacti后,可以看到左上角是两个
马哥linux学习笔记openssl的使用
马哥linux学习笔记:openssl的使用 linux中主要通过openssl,gpg等工具来实现加密解密机制,这里我只介绍下openssl的使用方法: openssl主要由三部分组成: libencrypto库 libssl库 openssl多用途命令行工具 前两种是开发调用openssl功能时专用的一些接口,
马哥linux学习笔记htop命令使用详解
马哥linux学习笔记:htop命令使用详解 htop工具在centos官方yum源仓库中是不提供的,但在epel的yum源仓库中是有的,所以我们可以通过源码编译安装htop,也可以设置epel的yum源来用yum命令安装htop,设置epel的yum源方法为: 首先,下载epel官方网站提供的rpm
马哥linux学习笔记ps命令使用
马哥linux学习笔记:ps命令使用 ps命令能够给出当前系统进程的快照,他能捕获系统在某一刻的进程状态,如果要想不断更新查看这个状态,就要使用top命令或借助于watch命令了: ps命令支持三种使用的语法格式 1.UNIX 风格,选项可以组合在一起,并且选项前必须
马哥linux学习笔记sed工具使用详解
马哥linux学习笔记:sed工具使用详解 sed是linux中号称文本处理三剑客的其中之一,是分交互式的文本流编辑器,可以对文本文件和标准输入进行编辑,整个处理过程是 sed由标准输入或文本文件读入一行资料并放入pattern space(模式空间)中,sed依照sed script
马哥linux学习笔记top命令的使用
马哥linux学习笔记:top命令的使用 top命令是Linux下常用的性能分析工具,能够实时显示系统中各个进程的资源占用状况,类似于Windows的任务管理器。下边详细介绍这款古老工具的使用方法: 在命令行下直接键入top命令,回车进入top出来的系统相关信息: 信息
Java 8 新特性,Lambda,方法引用,Stream,Optional
Java 8 新特性,Lambda,方法引用,Stream,Optional 为什么80%的码农都做不了架构师? 在C++、Python等语言里都有Lambda表达式,Java 8也新增了这一特性。 在java给变量赋值是这样的: int num=123;String str=hello world!;Boolean flag=str.startsWith(h);