欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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

结果只展示了最重要的一部分,在本例中,有两条线程,一条打蜡,一条抛光,因为是先打蜡,所以,可以等打完腊,等待状态改变被唤醒,而打完腊的时候,就会通知所有线程检查状态,做点对应的什么事情,在检查状态是否将本线程挂起,释放锁,

抛光其实也一样,只是抛光是在后面,所以必须要先检查状态,在决定是否抛光,这样,就能够控制到同步的效果