wait()、notify()方法详解

简介

wait()notify() 方法可用于控制线程的生命周期

详解

1、wait() 不带参数

当前线程 中调用 A对象wait() 方法,此时 当前线程 会进入 等待状态,此时 当前线程 会释放所持有的 锁资源,等到 其它线程 调用 A对象notify() 或者 notifyAll() 进行唤醒,当前线程 才有可能重新拿到 锁资源 并继续执行。

a、调用 wait() 与 notify() 的不是同一个对象-错误

/**
 * 调用 wait()、notify() 的不是同一个对象
 */
public class WaitDetail01Main {
    public static void main(String[] args) {
        WaitDetail01 t1 = new WaitDetail01();
        WaitDetail01 t2 = new WaitDetail01();
        t1.setFlag(true);
        t2.setFlag(false);
        t1.setName("A");
        t2.setName("B");
        t1.start();
        t2.start();
    }
}

class WaitDetail01 extends Thread{
    static Object o1 = new Object();
    private boolean flag;

    public void setFlag(boolean flag) {
        this.flag = flag;
    }

    @Override
    public void run() {
        if(flag){
            synchronized (this){
                try {
                    // 当前 this 为 A线程对象
                    // 线程B对象调用 notify() 不会唤醒 线程A
                    // 一直等待
                    this.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("线程 " + Thread.currentThread().getName() + " 进入 1...");
            }
        }else{
            // B线程
            synchronized (this){
                System.out.println("线程 " + Thread.currentThread().getName() + " 进入 2...");
                // 当前 this 为 线程B对象
                this.notify();
            }
        }
    }
}

解析:调用 wait()notify() 的必须是 同一个对象

b、当前线程未持有锁对象,去调用 wait()、notify()-错误

/**
 * 当前线程未持有锁,去调用 wait()、notify()
 */
public class WaitDetail02Main {
    public static void main(String[] args) {
        WaitDetail02 t1 = new WaitDetail02();
        WaitDetail02 t2 = new WaitDetail02();
        t1.setFlag(true);
        t2.setFlag(false);
        t1.setName("A");
        t2.setName("B");
        t1.start();
        t2.start();
    }
}

class WaitDetail02 extends Thread{
    static Object o1 = new Object();
    private boolean flag;

    public void setFlag(boolean flag) {
        this.flag = flag;
    }

    @Override
    public void run() {
        if(flag){
            try {
                // A线程
                // 未持有 o1 锁对象,调用 wait()
                // 抛出 IllegalMonitorStateException
                o1.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            synchronized (o1){
                System.out.println("线程 " + Thread.currentThread().getName() + " 进入 1...");
            }
        }else{
            // B线程
            // 未持有 o1 锁对象,调用 notify()
            // 抛出 IllegalMonitorStateException
            o1.notify();
            synchronized (o1){
                System.out.println("线程 " + Thread.currentThread().getName() + " 进入 2...");
            }
        }
    }
}

解析:在当前线程中调用 wait()notify() 方法之前,必须保证当前线程 此时 已经持有了 锁对象,否则抛出 IllegalMonitorStateException


2、wait() 带参数

wait(long timeout) 带一个参数:指定一个超时时间,在 当前线程 中调用 A对象wait(50) 方法,此时 当前线程 会进入 等待状态,此时 当前线程 会释放所持有的 锁资源,等到 50毫秒 时间到了之后,自动被唤醒,才有可能重新拿到 锁资源 并继续执行。

a、wait() 带参数-正确

/**
 * wait() 带参数
 */
public class WaitDetail03Main {
    public static void main(String[] args) {
        WaitDetail03 t1 = new WaitDetail03();
        WaitDetail03 t2 = new WaitDetail03();
        t1.setFlag(true);
        t2.setFlag(false);
        t1.setName("A");
        t2.setName("B");
        t1.start();
        t2.start();
    }
}

class WaitDetail03 extends Thread{
    static Object o1 = new Object();
    static Object o2 = new Object();
    private boolean flag;

    public void setFlag(boolean flag) {
        this.flag = flag;
    }

    @Override
    public void run() {
        if(flag){
            synchronized (o1){
                try {
                    // 等待 50 毫秒后 自动唤醒
                    // 50 毫秒后,B线程已经执行完毕并释放了锁资源 o1
                    // 此时 线程A 被自动唤醒,并重新获取锁资源 o1
                    o1.wait(50);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("线程 " + Thread.currentThread().getName() + " 进入 1...");
            }
        }else{
            synchronized (o1){
                System.out.println("线程 " + Thread.currentThread().getName() + " 进入 2...");
            }
        }
    }
}

解析:wait() 带参数的方法不需要满足:wait()notify() 的调用者是同一个对象,因为它不会 显示调用 notify();但还是必须满足:在当前线程中调用 wait() 带参数的方法之前,必须保证当前线程 此时 已经持有了 锁对象,否则抛出 IllegalMonitorStateException


3、notify()

随机唤醒某个因为执行了 wait() 方法而在 等待区 等待的线程

4、notifyAll()

唤醒所有因为执行了 wait() 方法而在 等待区 等待的线程

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章