当使用线程来同时运行多个任务时,可以通过使用锁(互斥) 来同步两个任务的行为, 从而使得一个任务不会干涉另一个任务的资源。 也就是说如果两个任务在交替着步入某项共享资源, 你可以使用互斥来使腹任何时刻只有一个任务可以访问 该资源.
第一步. 当任务协作时, 关键问题是这些任务之间的握手. 为了实现这种握手,要使用线程的基础特性: 互斥。 互斥能够确保只有一个任务可以响应某个信号,这样可以去除 任何可能的竞争条件。 在互斥基础上,我们为任务添加了一种途么,可以将其自身挂起,直至某些外部条件发生变化, 表示是时候让这个任务再接着运行了。
第二步. 任务间的握手,可以通过Object 的 wait()和 notify() 来安全地实现, 在Java的并发类库中, 还提供了具有 await() 和 signal() 方法的Condition对象.
第三步. wait() 可以等待某个条件发生变化, 很显然,改变这个条件超出了当前方法的控制能力. 通常这种条件将由另一个任务来改变.
因此, wait() 提供了一种在任务之间对活动同步的方式, 即让操作按顺序 一步一步执行。
调用sleep() 时,锁并没有被释放, yield() 也属于这种情况. 另一方面看, 当一个任务在方法里遇到了对wait () 的调用的时候, 线程的执行被挂起,对象上的锁被释放。 这就意味着另一个任务可以获得这个锁。
(1) 有两种形式的wait(). 第一种形式使用毫秒作为参数, 表示经此期间暂停, 与sleep() 不同的是, 对于wait() 而言:
a. 在wait() 期间对象锁是释放的
b. 可以通过nofity(), notifyAll(), 或者令时间到期, 从wait() 中恢复执行.
第二种形式,更常用的wait() 不带参数, 这种wait() 将无限等待下去, 直到接收到 notify(), notifyAll() 消息
注意: 从wait(), notify(), notifyAll()属于Object 的方法可知, 可以把wait()放进任何同步控制方法里, 而不用考虑该类是否与Thread, Runnable有关 . 实际上,只能在同步控制流程里调用wait(), notify(), notifyAll(), 如果在非同步控制方法里调用, 程序运行时将 抛出 illegalMonitorStateException,并伴随一些含糊的信息, 比如 "当前线程不是拥有者" , 异常信息表示: 调用 wait(), notify() 和notifyAll() 的任务在调用这些方法前必须 "拥有" 对象的锁。
第四步. 可以让一个对象执行某种操作以维护其自己的锁。 必须首先得到对象的锁, 如果要向对象 x 发送notifyAll(), 那么就必须在能够取得x 的锁的同步控制块中 这么做:
synchronized(x) {
x.notifyAll();
}
现在看一个简单的示例, 业务:执行两个操作,一个将蜡涂(wax)在汽车上, 一个抛光它, 抛光(buff)任务在涂蜡任务完成之前,是不能执行的, 而涂蜡任务在涂另一层蜡之前必须等待抛光完成, 示意图:
WaxOn 和WaxOff 都使用了Car 对象,该对象在这些任务等待条件变化的时候,使用wait() 和notifyAll() 来挂起和重新启动这些任务.
package concurrency.waxomatic;
import java.util.concurrent.*;
import static net.mindview.util.Print.*;
class Car {
private boolean waxOn = false;
public synchronized void waxed() { //"涂蜡" 动作
waxOn = true; // Ready to buff
notifyAll();
}
public synchronized void buffed() { //"抛光" 动作
waxOn = false; // Ready for another coat of wax
notifyAll();
}
public synchronized void waitForWaxing()
throws InterruptedException {
while(waxOn == false)
wait();
}
public synchronized void waitForBuffing()
throws InterruptedException {
while(waxOn == true)
wait();
}
}
class WaxOn implements Runnable { //涂蜡
private Car car;
public WaxOn(Car c) { car = c; }
public void run() {
try {
while(!Thread.interrupted()) {
printnb("Wax On! ");
TimeUnit.MILLISECONDS.sleep(200);
car.waxed();
car.waitForBuffing(); //等待抛光
}
} catch(InterruptedException e) {
print("Exiting via interrupt");
}
print("Ending Wax On task");
}
}
class WaxOff implements Runnable { //抛光
private Car car;
public WaxOff(Car c) { car = c; }
public void run() {
try {
while(!Thread.interrupted()) {
car.waitForWaxing(); //等待涂蜡
printnb("Wax Off! ");
TimeUnit.MILLISECONDS.sleep(200);
car.buffed();
}
} catch(InterruptedException e) {
print("Exiting via interrupt");
}
print("Ending Wax Off task");
}
}
public class WaxOMatic {
public static void main(String[] args) throws Exception {
Car car = new Car();
ExecutorService exec = Executors.newCachedThreadPool();
exec.execute(new WaxOff(car));
exec.execute(new WaxOn(car));
TimeUnit.SECONDS.sleep(5); // 运行5秒钟 时长
exec.shutdownNow(); // Interrupt all tasks
}
}
下载代码请参见: http://mindview.net/Books/TIJ4