在之前的Java并发(一)wait()与notifyAll()一文中的例子中,我们使用了wait()和notifyAll()来模拟了给汽车打蜡和抛光的情景。在JavaSE5中,还提供了java.util.concurrent.locks.Condition对象供我们使用。你可以在Condition上调用await()来挂起一个任务。当外部条件发生变化,意味着某个任务应该继续执行时,你可以通过调用signal()来通知这个任务,或者调用signalAll()来唤醒所有在这个Condition上被其自身挂起的任务(与使用signal()相比,signalAll()是更安全的方式)。
下面是WaxOnMatic.java的重写版本,它包含了一个Condition,用来在waitForWaxing()或waitForBuffing()内部挂起一个任务:
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
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
|
import
java.util.concurrent.ExecutorService;
import
java.util.concurrent.Executors;
import
java.util.concurrent.TimeUnit;
import
java.util.concurrent.locks.Condition;
import
java.util.concurrent.locks.Lock;
import
java.util.concurrent.locks.ReentrantLock;
class
Car {
private
Lock lock =
new
ReentrantLock();
private
Condition condition = lock.newCondition();
private
boolean
waxOn =
false
;
//是否上蜡
//上蜡
public
void
waxed() {
lock.lock();
try
{
waxOn =
true
;
condition.signalAll();
}
finally
{
lock.unlock();
}
}
//抛光
public
void
buffed() {
lock.lock();
try
{
waxOn =
false
;
condition.signalAll();
}
finally
{
lock.unlock();
}
}
//等待上蜡
public
void
waitForWaxing()
throws
InterruptedException {
lock.lock();
try
{
while
(waxOn ==
false
) {
condition.await();
}
}
finally
{
lock.unlock();
}
}
//等待抛光
public
void
waitForBuffing()
throws
InterruptedException {
lock.lock();
try
{
while
(waxOn ==
true
) {
condition.await();
}
}
finally
{
lock.unlock();
}
}
}
class
WaxOnTask
implements
Runnable {
private
Car car;
private
String name;
public
WaxOnTask(String name, Car car) {
this
.name = name;
this
.car = car;
}
@Override
public
void
run() {
try
{
while
(!Thread.interrupted()) {
System.out.println(
"["
+ name +
"] is Wax on!"
);
//正在上蜡
TimeUnit.MILLISECONDS.sleep(
300
);
car.waxed();
//上蜡完成
car.waitForBuffing();
//等待抛光
}
}
catch
(InterruptedException e) {
System.out.println(
"["
+ name +
"] Exiting WaxOnTask via interrupt."
);
}
}
}
class
BuffTask
implements
Runnable {
private
Car car;
private
String name;
public
BuffTask(String name, Car car) {
this
.name = name;
this
.car = car;
}
@Override
public
void
run() {
try
{
while
(!Thread.interrupted()) {
car.waitForWaxing();
//等待上蜡
System.out.println(
"["
+ name +
"] Buffing..."
);
//正在抛光
TimeUnit.MILLISECONDS.sleep(
300
);
car.buffed();
//抛光完成
}
}
catch
(InterruptedException e) {
System.out.println(
"["
+ name +
"] Exiting BuffTask via interrupt."
);
}
}
}
public
class
WaxOMatic2 {
public
static
void
main(String[] args)
throws
Exception {
Car car =
new
Car();
ExecutorService exec = Executors.newCachedThreadPool();
//上蜡
exec.execute(
new
WaxOnTask(
"Waxx"
, car));
//抛光
exec.execute(
new
BuffTask(
"Buff"
, car));
//运行一段时间,停止ExecutorService
TimeUnit.SECONDS.sleep(
3
);
exec.shutdownNow();
}
}
|
执行结果:
1
2
3
4
5
6
7
8
9
10
11
12
|
[Waxx] is Wax on!
[Buff] Buffing...
[Waxx] is Wax on!
[Buff] Buffing...
[Waxx] is Wax on!
[Buff] Buffing...
[Waxx] is Wax on!
[Buff] Buffing...
[Waxx] is Wax on!
[Buff] Buffing...
[Buff] Exiting BuffTask via interrupt.
[Waxx] Exiting WaxOnTask via interrupt.
|
从代码中可以看到,Car的构造器中,单个的Lock将产生一个Condition对象,这个对象被用来管理任务之间的通信。但是,这个Condition对象不包含任何有关处理状态的信息,因此你需要管理额外的表示处理状态的信息,即boolean waxOn。
注意:每个lock()的调用都必须紧跟一个try-finally子句,用来保证在所有情况下都可以释放锁。在使用内建版本时,任务在可以调用await(),signal()或signalAll()之前,必须拥有这个锁。
另外还需要注意的是,这个解决方案比之前一个更加复杂,在本例中这种复杂性并未使你收获更多。Lock和Condition对象只有在更加困难的多线程问题中才是必需的。