使用CountDownLatch模拟高并发

刚学到这招,记录一下。

以前只知道闭锁就用来阻塞住主线程,然后等其他线程运行完,计数器到0的时候,放开闭锁,没想到还能这么玩儿。

这里还正好用来测试下单例在多线程下的问题,可以很明显的看到2个线程同时并发获取单例的时候,就会很大概率得到的不是一个对象了,这时候用同步方法、枚举、静态内部类或DCL就能解决这个问题。

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
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

class CountDownLatchUtil {
private CountDownLatch start;
private CountDownLatch end;
private int count;

public CountDownLatchUtil() {
this(1);
}

public CountDownLatchUtil(int count) {
start = new CountDownLatch(1);
end = new CountDownLatch(count);
this.count = count;
}

public void latch(TaskFunction taskFunction) {
ExecutorService pool = Executors.newFixedThreadPool(count);
for (int i = 1; i <= count; ++i) {
Runnable task = new Runnable() {
@Override
public void run() {
try {
start.await();
taskFunction.task();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
end.countDown();
}
}
};
pool.submit(task);
}
start.countDown();
try {
end.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
pool.shutdown();
}

@FunctionalInterface
public static interface TaskFunction {
void task();
}
}

class Obj {
private static Obj obj;

private Obj() {
};

public static Obj getInstance() {
if (obj == null) {
obj = new Obj();
}
return obj;
}
}

public class Main {

public static void main(String[] args) {
CountDownLatchUtil latchUtil = new CountDownLatchUtil(2);
long time = System.currentTimeMillis();
latchUtil.latch(() -> {
System.out.println(Obj.getInstance());
// Obj.getInstance();
});
System.out.println("运行耗时:" + (System.currentTimeMillis() - time) + "ms");
}
}

输出:

Obj@6299d4f3
Obj@7f5b7c1b
运行耗时:47ms

文章作者: Shawn Qin
文章链接: https://qinshuang1998.github.io/2019/04/30/java-latch-virtual/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Shawn's Blog