wait()和notify()等待唤醒

226 阅读2分钟

前言

在Java中,若要实现程序的等待唤醒机制,可以使用jdk提供的wait()等待、notify()或者notifyAll()唤醒方法

等待唤醒

用法

使用wait()和notify()实现程序等待唤醒

public class LockDemo {
    static final Object object = new Object();
 
    public static void main(String[] args) {
        new Thread(() -> {
            synchronized (object) {
                System.out.println(Thread.currentThread().getName() + ":开始执行");
                try {
                    // 使当前线程等待
                    object.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + ":执行结束");
            }
        }, "A").start();
 
        new Thread(() -> {
            synchronized (object) {
                System.out.println(Thread.currentThread().getName() + "==>开始唤醒");
                // 使当前线程唤醒
                object.notify();
                System.out.println(Thread.currentThread().getName() + ":唤醒结束");
            }
        }, "B").start();
    }
}

notify()方法只能唤醒一个wait(),如果存在多个的话,只能唤醒一个,如

public class Lock2Demo {
    static Object object = new Object();
 
    public static void main(String[] args) {
        new Thread(() -> {
            synchronized (object) {
                System.out.println(Thread.currentThread().getName() + ":开始执行");
                try {
                    // 使当前线程等待
                    object.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + ":执行结束");
            }
        }, "A").start();

        new Thread(() -> {
            synchronized (object) {
                System.out.println(Thread.currentThread().getName() + ":开始执行");
                try {
                    // 使当前线程等待
                    object.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + ":执行结束");
            }
        }, "C").start();

        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
 
        new Thread(() -> {
            synchronized (object) {
                System.out.println(Thread.currentThread().getName() + ":开始唤醒");
                // 使当前线程唤醒
                object.notify();
                System.out.println(Thread.currentThread().getName() + ":唤醒结束");
            }
        }, "B").start();
    }
}

输出结果为

image.png 要唤醒多个的话,使用notifyAll()方法,如

public class Lock2Demo {
    static Object object = new Object();
 
    public static void main(String[] args) {
        new Thread(() -> {
            synchronized (object) {
                System.out.println(Thread.currentThread().getName() + ":开始执行");
                try {
                    // 使当前线程等待
                    object.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + ":执行结束");
            }
        }, "A").start();

        new Thread(() -> {
            synchronized (object) {
                System.out.println(Thread.currentThread().getName() + ":开始执行");
                try {
                    // 使当前线程等待
                    object.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + ":执行结束");
            }
        }, "C").start();

        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
 
        new Thread(() -> {
            synchronized (object) {
                System.out.println(Thread.currentThread().getName() + ":开始唤醒");
                // 使当前线程唤醒
                object.notifyAll();
                System.out.println(Thread.currentThread().getName() + ":唤醒结束");
            }
        }, "B").start();
    }
}

输出结果为

image.png 备注,wait()、notify()或者notifyAll()这三个方法,必须要加锁synchronized()修饰,否则会报错

public class Lock3Demo {
    static Object object = new Object();
 
    public static void main(String[] args) {
        new Thread(() -> {
            try {
                // 使当前线程等待
                object.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }, "A").start();

 
        new Thread(() -> {
            System.out.println(Thread.currentThread().getName() + ":开始唤醒");
            // 使当前线程唤醒
            object.notifyAll();
            System.out.println(Thread.currentThread().getName() + ":唤醒结束");
        }, "B").start();
    }
}

会报以下错误

image.png 必须配合synchronized使用,否则抛出IllegalMonitorStateException异常

总结

合理使用Java的等待唤醒机制,可以更好的编码,而且等待唤醒调用顺序不能改变,必须加锁修饰