Hexsmith's blog

业精于勤荒于嬉,行成于思毁于随!

0%

Java代码模拟高并发操作

Java通过代码模拟高并发可以以最快的方式发现我们系统中潜在的线程安全性问题,此处使用Semaphore(信号量)和 CountDownLatch(闭锁)搭配ExecutorService(线程池)来进行模拟

Semaphore

JDK 1.5之后会提供这个类,Semaphore是一种基于计数的信号量。它可以设定一个阈值,基于此,多个线程竞争获取许可信号,做完自己的申请后归还,超过阈值后,线程申请许可信号将会被阻塞。Semaphore可以用来构建一些对象池,资源池之类的,比如数据库连接池,我们也可以创建计数为1的Semaphore,将其作为一种类似互斥锁的机制,这也叫二元信号量,表示两种互斥状态。其原理图如下:
Semaphore原理图

CountDownLatch

JDK 1.5之后会提供这个类,CountDownLatch这个类能够使一个线程等待其他线程完成各自的工作后再执行。例如,应用程序的主线程希望在负责启动框架服务的线程已经启动所有的框架服务之后再执行。CountDownLatch是通过一个计数器来实现的,计数器的初始值为线程的数量。每当一个线程完成了自己的任务后,计数器的值就会减1。当计数器值到达0时,它表示所有的线程已经完成了任务,然后在闭锁上等待的线程就可以恢复执行任务。
其原理图如下:
CountDownLatch原理图

以上两个类可以搭配使用,达到模拟高并发的效果,以下使用代码的形式进行举例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
/**
* 使用{@link Semaphore}和{@link CountDownLatch}模拟并发请求
* @author hexsmith
* @version v1.0
* @see Semaphore
* @see CountDownLatch
* @see ExecutorService
* @since 2018/8/6 22:44
*/
public class ConcurrentCountExample {

/**
* 请求总数
*/
private static final int CLIENT_TOTAL = 5000;

/**
* 同时并发执行的线程数
*/
private static final int THREAD_TOTAL = 200;

/**
* 由于是多线程并行操作count,因此要使用原子操作
*/
private static AtomicInteger count = new AtomicInteger(0);

public static void main(String[] args) throws InterruptedException {

ExecutorService executorService = Executors.newCachedThreadPool();
// 信号量,用户控制并发线程数
final Semaphore semaphore = new Semaphore(THREAD_TOTAL);
// 闭锁,实现计数器递减
final CountDownLatch countDownLatch = new CountDownLatch(CLIENT_TOTAL);
for (int i = 0;i<CLIENT_TOTAL;i++){
executorService.execute(()->{
try {
// 获取执行许可,当许可不超过200时,允许通过,否则线程阻塞等待,直到获取许可
semaphore.acquire();
add();
// 释放许可
semaphore.release();
} catch (InterruptedException e) {
e.printStackTrace();
}
// 闭锁减一
countDownLatch.countDown();
});
}
// main线程阻塞等待,知道闭锁值为0才继续向下执行
countDownLatch.await();
executorService.shutdown();
System.out.println("count = " + count);

}

/**
* 计数统计
*/
private static void add(){
count.incrementAndGet();
}

}
------------- 本文结束 感谢您的阅读 -------------