【Java多线程】wait方法和notify方法

目录

前言:

1.wait方法

wait结束等待的条件:

1)wait()不带参数

2)wait(long timeout)带参数

 3)其他线程调⽤该等待线程的interrupted⽅法,?导致wait抛出 InterruptedException 异常.

2.notify()方法

notify()⽅法

notifyAll()⽅法 

3.wait和sleep的对⽐(⾯试题)


前言:

线程是抢占式执行的,无法预知线程之间的执行顺序。线程是随机调度。

但有时程序员也希望能合理协调多个线程的执行顺序。

因此,在 Java 中使用了等待(wait)通知(notify)机制,用于在应用层面上干预多个线程的执行顺序。

完成这个协调⼯作, 主要涉及到三个⽅法

  • wait() / wait(long timeout):  让当前线程进⼊等待状态.
  • notify() / notifyAll():  唤醒在当前对象上等待的线程.

注意:wait,notify,notifyAll都是Object类的方法 


1.wait方法

• 使当前执⾏代码的线程进⾏等待.(把线程放到等待队列中)
• 释放当前的锁
• 满⾜⼀定条件时被唤醒,重新尝试获取这个锁.

wait要搭配synchronized来使⽤.脱离synchronized使⽤wait会直接抛出异常. 


代码⽰例:观察wait()⽅法使⽤:

wait结束等待的条件:

1)wait()不带参数
public class demo4 {
    public static void main(String[] args) throws InterruptedException {
        Object object = new Object();
        synchronized (object) {
            System.out.println("等待中");
            object.wait();
            System.out.println("等待结束");
        }
    }
}

  这样在执⾏到object.wait()之后就⼀直等待下去,那么程序肯定不能⼀直这么等待下去了

2)wait(long timeout)带参数
public class demo4 {
    public static void main(String[] args) throws InterruptedException {
        Object object = new Object();
        synchronized (object) {
            System.out.println("等待中");
            object.wait(1000);
            System.out.println("等待结束");
        }
    }
}
等待中
等待结束

Process finished with exit code 0
 3)其他线程调⽤该等待线程的interrupted⽅法,?导致wait抛出 InterruptedException 异常.
public class demo4 {
    public static void main(String[] args) {
        //创建锁对象;
        Object locker = new Object();

        Thread t1 = new Thread(() -> {
            System.out.println("wait前");
            //在 synchronized 代码块中调用 wait 方法;
            synchronized (locker) {
                // wait 方法是由锁对象调用的,调用后,线程释放锁,进入等待队列;
                try {
                    locker.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("wait后");
        });
        t1.start();
        //抛出异常,清除中断标志,唤醒t1线程。
        t1.interrupt();
    }
}

 4)使用notify方法唤醒


2.notify()方法

notify⽅法是唤醒等待的线程.

  • ⽅法notify()也要在同步⽅法或同步块中调⽤,该⽅法是⽤来通知那些可能等待该对象的对象锁的其它线程,对其发出通知notify,并使它们重新获取该对象的对象锁。
  • 如果有多个线程等待,则有线程调度器随机挑选出⼀个呈wait状态的线程。(并没有"先来后到")
  • 在notify()⽅法后,当前线程不会⻢上释放该对象锁,要等到执⾏notify()⽅法的线程将程序执⾏完,也就是退出同步代码块之后才会释放对象锁。
notify()⽅法
public class demo4 {
    public static void main(String[] args) {
        //创建锁对象;
        Object locker = new Object();
        Thread t1 = new Thread(()->{
            System.out.println("t1 wait前!");
            synchronized (locker) {
                try {
                    locker.wait();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
            System.out.println("t1 wait后!");
        });

        Thread t2 = new Thread(()-> {
            try {
                Thread.sleep(1000);
                System.out.println("t2 notify 之前");
                //让 t1 线程有时间进入到wait状态
                synchronized (locker) {
                    locker.notify();
                    System.out.println("t2 notify 之后");
                }
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        });
        t1.start();
        t2.start();
    }
}
t1 wait前!
t2 notify 之前
t2 notify 之后
t1 wait后!

Process finished with exit code 0

notifyAll()⽅法 

使用notifyAll()⽅法 可以唤起所有的线程

    public static void main(String[] args) throws InterruptedException {
        Object locker = new Object();
        Thread t1 = new Thread(()->{
            System.out.println("t1 wait!");
            synchronized (locker) {
                try {
                    locker.wait();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
            System.out.println("t1 over!");
        });
        Thread t2 = new Thread(()->{
            System.out.println("t2 wait!");
            synchronized (locker) {
                try {
                    locker.wait();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
            System.out.println("t2 over!");
        });
        Thread t3 = new Thread(()->{
            System.out.println("t3 wait!");
            synchronized (locker) {
                try {
                    locker.wait();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
            System.out.println("t3 over!");
        });
        Thread t4 = new Thread(()->{
            synchronized (locker) {
                System.out.println("t4 唤起所有线程");
                locker.notifyAll();
            }
        });
        t1.start();
        t2.start();
        t3.start();
        Thread.sleep(1000);
        t4.start();
    }

 

添加 Thread.sleep(1000) 后,程序会稍微暂停 1 秒钟,确保 t1t2t3 线程已经进入 wait() 方法并且已经释放了 locker 锁。这样,在 t4 线程调用 notifyAll() 时,locker 锁已经被释放,t4 可以成功获取锁并调用 notifyAll() 来唤醒所有等待的线程,从而避免了死锁。 


3.wait和sleep的对⽐(⾯试题)

 

特性wait()sleep()
来源Object 类的实例方法Thread 类的静态方法
锁的释放会释放对象锁不释放锁
线程状态进入等待状态(Waiting)进入休眠状态(Sleeping)
使用场景线程间通信与协调(如生产者-消费者)控制线程暂停时间、模拟延时等
中断处理抛出 InterruptedException抛出 InterruptedException
参数可以指定等待时间(毫秒、纳秒)可以指定休眠时间(毫秒、纳秒)
是否需要同步需要在同步代码块或同步方法中调用不需要同步
影响线程调度影响线程的调度,直到线程被唤醒影响线程调度,直到指定时间过后
线程恢复通过 notify() 或 notifyAll() 唤醒休眠时间到达后自动恢复

 总结:

  1. 调用对象wait()Object 类的一个方法,它必须在同步块或同步方法中调用,用于释放当前线程持有的锁,并使线程进入等待队列,直到其他线程调用同一对象的 notify()notifyAll() 方法。而 sleep()Thread 类的静态方法,线程调用时不需要持有锁,它会让当前线程休眠指定的时间。

  2. 释放锁wait() 会释放对象的锁,而 sleep() 不会释放锁。

  3. 目的wait() 主要用于线程间的通信,线程进入等待状态直到被唤醒;sleep() 主要用于控制线程的暂停时间,通常不用于线程间的协调。


 结语: 写博客不仅仅是为了分享学习经历,同时这也有利于我巩固知识点,总结该知识点,由于作者水平有限,对文章有任何问题的还请指出,接受大家的批评,让我改进。同时也希望读者们不吝啬你们的点赞+收藏+关注,你们的鼓励是我创作的最大动力!

评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值