Loading

java多线程——线程通信wait与notify

waitnotifynotifyAll 三个方法均必须在synchronized 下才是使用,而且调用方必须是synchronized 锁对象,如果是其他对象调用,则会报错

notifynotifyAll所唤醒的线程是同一个锁对象的等待状态的线程

一个例子

class Patient implements Runnable {
    //生病 生病后唤醒医生给病人治病
    public synchronized void ill() {
        Hospital.patientNumber++;
        System.out.println("get cold  --->" + Hospital.patientNumber);
        notifyAll();
    }

    @Override
    public void run() {
        ill();
    }
}

class Doctor implements Runnable {
    //治疗 如果没有病人就等待 如果有就被唤醒 给人治病
    public synchronized void treat() throws InterruptedException {
        while (Hospital.patientNumber <= 0) {
            wait();
        }
        Hospital.patientNumber--;
        System.out.println("drink more hot water  --->" + Hospital.patientNumber);
    }

    @Override
    public void run() {
        try {
            treat();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

class Hospital {
    public static int patientNumber = 0;
}

public class WaitAndNotifyTest {

    public static void main(String[] args) {
        Patient patient = new Patient();
        Doctor doctor = new Doctor();

        for (int i = 0; i < 10; i++) {
            new Thread(doctor).start();
        }

        for (int i = 0; i < 10; i++) {
            new Thread(patient).start();
        }
    }
}

结果是
在这里插入图片描述
原因就是两个函数的锁对象不同,所以病人生病并不能唤醒医生(其实,锁对象不同 对于Hospital.patientNumber这个变量的修改并没有有效的同步保护,只是Doctor和Doctor线程、Patient和Patient线程之间不能同时访问,因为是同一个锁,但是Doctor和Patient线程之间还是有可能同时访问,因为他们的锁不同)

修改代码如下:

class Patient implements Runnable {
    //生病 生病后唤醒医生给病人治病
    public void ill() {
        synchronized (Hospital.class) {//注意锁的变化
            Hospital.patientNumber++;
            System.out.println("get cold  --->" + Hospital.patientNumber);
            Hospital.class.notifyAll();//注意调用对象的变化
        }
    }

    @Override
    public void run() {
        ill();
    }
}

class Doctor implements Runnable {
    //治疗 如果没有病人就等待 如果有就被唤醒 给人治病
    public void treat() {
        synchronized (Hospital.class) {//注意锁的变化
            while (Hospital.patientNumber <= 0) {
                try {
                    Hospital.class.wait();//注意调用对象的变化
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            Hospital.patientNumber--;
            System.out.println("drink more hot water  --->" + Hospital.patientNumber);
        }
    }

    @Override
    public void run() {
        treat();
    }
}

class Hospital {
    public static int patientNumber = 0;
}

public class WaitAndNotifyTest {

    public static void main(String[] args) {
        Patient patient = new Patient();
        Doctor doctor = new Doctor();

        for (int i = 0; i < 10; i++) {
            new Thread(doctor).start();
        }

        for (int i = 0; i < 10; i++) {
            new Thread(patient).start();
        }
    }
}

结果如下:
在这里插入图片描述

如果遇到错误java.lang.IllegalMonitorStateException:说明synchronized的锁对象和调用wait还有notify的对象不一致(因为Wait()需要释放锁,如果调用的对象不是这个锁对象就无法释放掉这个锁)

posted @ 2021-03-30 16:09  克豪  阅读(79)  评论(0)    收藏  举报