Thinking in java 第21章 并发 wait() 与 notifyAll()
程序员文章站
2022-05-07 08:37:27
...
wait 使你可以等待某个条件发生变化,而改变这个条件超出了当前方法的控制能力,通常,这种条件将由另一个任务来改变。你肯定不想在你的任务测试这个条件的同时,不断的进行空循环,这被称为忙等待,通常是一种不良的cpu周期使用方式。因此wait等待会在等待时将任务挂起,并且只有在notify或者notifyAll的时候才会会被唤醒并检查所发生的变化,因此,wait提供了一种在任务之间同步的方法。
调用sleep方法的时候,锁并没有被释放,调用yied()也时一样。而wait将释放掉这个锁。这一点很重要,其他需要这个锁的 互斥区可以被访问。
wait()与notify()属于Object,看起来有些奇怪,不过这是由道理的,因为这些方法操作的锁也时这个对象的一部分,所以,你可以把wait方法放进任何同步方法中,实际上,也只能在同步方法中调用wait,因为要操作锁,当你在非同步中使用wait()的时候,程序能够通过编译,但是在运行的时候经常出错。
让我们看一个简单的示例(我觉得不简单),car 代表一辆车,需要对它涂蜡 和 抛光,但是这两个程序是由步骤的,肯定是先涂蜡,在抛光,然后在涂蜡,这样子,不能没腊也抛光,有腊还继续涂蜡,下面是示例:
class Car{
//是否有腊
private boolean waxOn = false;
//打蜡,有腊,其他任务可以继续
public synchronized void waxed(){
waxOn = true;
//唤醒所有线程,检查状态,该干什么
notifyAll();
}
//抛光,没有腊,其他任务可以继续
public synchronized void buffed(){
waxOn = false;
//唤醒所有线程,检查状态,该干什么
notifyAll();
}
/**
*如果没有腊,此线程挂起
*
* @throws InterruptedException
*/
public synchronized void waitForWaxing() throws InterruptedException{
while(waxOn == false)
wait();
}
/**
*
* 有腊挂起
*
* @throws InterruptedException
*/
public synchronized void waitForBuffing() throws InterruptedException{
while(waxOn == true)
wait();
}
}
class WaxOn implements Runnable {
private Car car;
public WaxOn(Car c){
car = c;
}
@Override
public void run() {
try {
while(!Thread.interrupted()) {
//睡眠,更快退出线程
TimeUnit.MILLISECONDS.sleep(200);
//打蜡说明
System.out.println("Wax On!");
//打蜡
car.waxed();
//根据状态挂起此线程,释放锁,等待唤醒
car.waitForBuffing();
}
} catch (InterruptedException e) {
System.out.println("Exiting via interrupt");
}
System.out.println("Ending Wax On task");
}
}
class WaxOff implements Runnable {
private Car car;
public WaxOff(Car c){
car = c;
}
@Override
public void run() {
try {
while(!Thread.interrupted()) {
//如果没有腊,此线程挂起,释放锁,直到被唤醒
car.waitForWaxing();
//被唤醒,并且打上了腊
//抛光
System.out.println("Wax Off");
//睡眠,更快退出线程
TimeUnit.MILLISECONDS.sleep(200);
//汽车状态切换
car.buffed();
}
} catch (InterruptedException e) {
System.out.println("Exiting via interrupt");
}
System.out.println("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);
exec.shutdownNow();
}
}
Wax On!
Wax Off
Wax On!
Wax Off
Wax On!
Wax Off
Exiting via interrupt
Exiting via interrupt
Ending Wax Off task
Ending Wax On task
结果只展示了最重要的一部分,在本例中,有两条线程,一条打蜡,一条抛光,因为是先打蜡,所以,可以等打完腊,等待状态改变被唤醒,而打完腊的时候,就会通知所有线程检查状态,做点对应的什么事情,在检查状态是否将本线程挂起,释放锁,
抛光其实也一样,只是抛光是在后面,所以必须要先检查状态,在决定是否抛光,这样,就能够控制到同步的效果