整理下 Guava 对并发这块的封装。

Monitor

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
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
// 多个线程之间的等待和唤醒

// 1. 使用 synchronized 配合 Object 对象的 wait() 和 notifyAll()
public class SafeBox<T> {
private T value;

public synchronized void set(T newValue) throws InterruptedException {
while (value != null) { // 如果已经有值,则等待
wait();
}
this.value = newValue;
notifyAll();
}

public synchronized T get() throws InterruptedException {
while (value == null) {
wait();
}
T result = value;
value = null;
notifyAll();
return result;
}
}

// 2. 使用 ReentrantLock 以及它自带的 Condition,Condition 提供了 await() 和 signal() 方法,性能更好
public class SafeBox<T> {
private T value;
private final ReentrantLock lock = new ReentrantLock();
private final Condition valuePresent = lock.newCondition(); // 有值时的控制条件
private final Condition valueAbsent = lock.newCondition(); // 没有值时的控制条件

public void set(T newValue) throws InterruptedException {
lock.lock();
try {
while (value != null) {
valueAbsent.await();
}
value = newValue;
valuePresent.signal();
} finally {
lock.unlock();
}
}

public T get() throws InterruptedException {
lock.lock();
try {
while (value == null) {
valuePresent.await();
}
T result = value;
value = null;
valueAbsent.signal();
return result;
} finally {
lock.unlock();
}
}
}

// 3. 使用 Guava 提供的 Monitor,内部使用了 ReentrantLock,写法上更灵活,不再需要手写 while 循环
public class SafeBox<T> {
private final Monitor monitor = new Monitor();
private final Monitor.Guard valuePresent = new Monitor.Guard(monitor) {
public boolean isSatisfied() {
return value != null;
}
};
private final Monitor.Guard valueAbsent = new Monitor.Guard(monitor) {
public boolean isSatisfied() {
return value == null;
}
};
private T value;

public T get() throws InterruptedException {
monitor.enterWhen(valuePresent);
try {
T result = value;
value = null;
return result;
} finally {
monitor.leave();
}
}

public void set(T newValue) throws InterruptedException {
monitor.enterWhen(valueAbsent);
try {
value = newValue;
} finally {
monitor.leave();
}
}
}

Service