前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >【Java多线程】wait方法和notify方法

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

作者头像
用户11369558
发布2024-11-20 15:09:46
发布2024-11-20 15:09:46
8100
代码可运行
举报
文章被收录于专栏:JavaJava
运行总次数:0
代码可运行

前言:

线程是抢占式执行的,无法预知线程之间的执行顺序。线程是随机调度。 但有时程序员也希望能合理协调多个线程的执行顺序。 因此,在 Java 中使用了等待(wait)和通知(notify)机制,用于在应用层面上干预多个线程的执行顺序。

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

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

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


1.wait方法

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

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


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

wait结束等待的条件:
1)wait()不带参数
代码语言:javascript
代码运行次数:0
运行
复制
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)带参数
代码语言:javascript
代码运行次数:0
运行
复制
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("等待结束");
        }
    }
}
代码语言:javascript
代码运行次数:0
运行
复制
等待中
等待结束

Process finished with exit code 0
3)其他线程调⽤该等待线程的interrupted⽅法,?导致wait抛出 InterruptedException 异常.
代码语言:javascript
代码运行次数:0
运行
复制
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()⽅法
代码语言:javascript
代码运行次数:0
运行
复制
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();
    }
}
代码语言:javascript
代码运行次数:0
运行
复制
t1 wait前!
t2 notify 之前
t2 notify 之后
t1 wait后!

Process finished with exit code 0

notifyAll()⽅法

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

代码语言:javascript
代码运行次数:0
运行
复制
    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() 主要用于控制线程的暂停时间,通常不用于线程间的协调。

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

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2024-11-12,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言:
  • 1.wait方法
    • wait结束等待的条件:
  • 2.notify()方法
  • 3.wait和sleep的对⽐(⾯试题)
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档