多线程-线程的等待通知wait、notify

发布时间:2024年01月23日

目录

1.什么是线程的等待通知

2.wiat()方法

? ? 2.1 wait 做的事情:

2.2wait 结束等待的条件:

代码示例:

?2.3wait的三种重载方式

2.4 面试问题:wait()和sleep()之间的区别

3.notify()方法

3.1notify ?法是唤醒等待的线程.

?3.2wait 和notify之间的联系

?3.3notifyAll()


1.什么是线程的等待通知

? ? ? ? 线程的等待通知是多线程编程中常用的一种机制,用于线程之间的协作和同步。在Java中,线程的等待通知通过使用wait()notify()notifyAll()方法来实现。

? ? ? ? ?由于线程之间是抢占式执?的, 因此线程之间执?的先后顺序难以预知. 但是实际开发中有时候我们希望合理的协调多个线程之间的执?先后顺序,所以我们需要wait()、notify()来实现这些功能。

2.wiat()方法

? ? 2.1 wait 做的事情:

? 使当前执?代码的线程进?等待. (把线程放到等待队列中)
? 释放当前的锁
? 满??定条件时被唤醒, 重新尝试获取这个锁.
注意:wait 要搭配 synchronized 来使?. 脱离 synchronized 使? wait 会直接抛出异常.

2.2wait 结束等待的条件:

? 其他线程调?该对象的 notify ?法.
? wait 等待时间超时 (wait ?法提供?个带有 timeout 参数的版本, 来指定等待时间).
? 其他线程调?该等待线程的 interrupted ?法, 导致 wait 抛出 InterruptedException 异常.

代码示例:

package 多线程;

public class ThreadDemo18 {
    public static void main(String[] args) throws InterruptedException {
        Object object = new Object();//new一个对象
        synchronized (object){//对对象进行加锁
            System.out.println("等待中···");
            object.wait();//当前线程会释放对象的锁,并进入等待状态。
            System.out.println("等待结束。");
        }
    }
}

? ? ? ?主线程会打印"等待中···",然后调用object.wait()方法,释放对象的锁,并进入等待状态。当其他线程调用了object.notify()object.notifyAll()方法时,主线程会被唤醒,然后重新获取对象的锁,并继续执行输出"等待结束。"。但是这个代码种没有notify()方法,所以没有重新唤起线程,就没有输出等待结束。

?

?2.3wait的三种重载方式

? ? ? ? 第一种wait()重载方式:它是死等的,就是说如果没有notify()方法来唤醒它,它就一直处于阻塞状态。

? ? ? ? 第二种wait()重载方式:它自己设定了一个超时的时间,单位是ms。就是说它最多等待到设定的时间,在这个时间内没有notify也不等了,直接会被唤醒。

? ? ? ?第三种wait()重载方式:方法使当前线程进入等待状态,直到其他线程调用该对象notify()notifyAll()方法唤醒它,或者指定的超时时间到达。这个方法允许设置纳秒级别的超时时间,除了毫秒级别的参数外,还可以指定纳秒级别的增量。

2.4 面试问题:wait()和sleep()之间的区别

? ?wait提供了一个带超时间的版本? ?

? ? sleep也是可以指定时间? ? ? ? 都是时间到了解除阻塞。

wait和sleep都是可以提前被唤醒的

wait通过notify()来唤醒

sleep通过interrupt来唤醒

使用wait的主要目的,一定是不知道要等多少时间的前提下来使用的。所谓的超时间,其实是“兜底的”。

使用sleep,一定是知道要等多长时间,必须要等到那个时间才会被唤醒。?

3.notify()方法

3.1notify ?法是唤醒等待的线程.

? ?法notify()也要在同步?法或同步块中调?,该?法是?来通知那些可能等待该对象的对象锁的其 它线程,对其发出通知notify,并使它们重新获取该对象的对象锁。
? 如果有多个线程等待,则有线程调度器随机挑选出?个呈 wait 状态的线程。(并没有 "先来后到")
? 在notify()?法后,当前线程不会?上释放该对象锁,要等到执?notify()?法的线程将程序执? 完,也就是退出同步代码块之后才会释放对象锁。

?代码示例:

package 多线程;

public class ThreadDemo19 {
    public static void main(String[] args) {
        //需要一个统一的对象进行加锁,wait,notify
        Object locker = new Object();
        
        Thread t1 = new Thread(()->{
            synchronized (locker){
                System.out.println("t1 wait 之前");
                try {
                    locker.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("t1 wait 之后");
            }
        });
        Thread t2 = new Thread(()->{
            try {
                Thread.sleep(5000);
            synchronized (locker){
                System.out.println("t2 notify 之前");
                    locker.notify();
                System.out.println("t2 notify 之后");
                } 
                }
            catch (InterruptedException e) {
                e.printStackTrace();
                
            }
        });
    }
}

?1)?t1?执行起来之后,就会先立即拿到锁,并且打印t1?wait?之前,并进入wait?方法(释放锁+阻塞等待)

2)?t2?执行起来之后,先进行?sleep(5000)(这个?sleep?就可以让t1?能够先拿到锁)

3)?t2?sleep?结束之后,由于t1?是wait?状态,锁是释放的.t2?就能拿到锁
接下来打印t2?notify?之前,执行?notify?操作,这个操作就能唤醒t1.(此时t1?就从?WAITING状态恢复回来了)

4)但是由于?t2?此时还没有释放锁呢,t1?WAITING?恢复之后,尝试获取锁,就可能出现一个小小的阻塞.

5)?t2执行完?t2-motify?之后,释放锁,t2执行完毕.

所以输出结果如下:

?3.2wait 和notify之间的联系

wait 和notify之间是通过Object对象联系起来的。

Object1.wait()

Object2.notify() 此时如果用notify是无法被唤醒的,必须是两个对象一样才能唤醒。

Object1.wait()

Object2.wait()此时notify使用的哪个对象,哪个对象才能被唤醒。

?3.3notifyAll()

? ? ? ? ?唤醒这个对象上所有等待的线程.假设有很多个线程,都使用同一个对象?wait.针对这个对象进行?notifyAII,此时就会全都唤醒~~但是注意,这些线程在wait返回的时候,要重新获取锁,就会因为锁的竞争,使这些线程实际上是一个一个串行执行的.

具体使用方式如下:

  1. notifyAll()方法必须在同步代码块或同步方法中调用,并且只能应用于被synchronized关键字修饰的对象上。

  2. 当调用对象的notifyAll()方法时,该对象上所有等待的线程都会被唤醒,并尝试重新获取对象的锁。

  3. 被唤醒的线程会进入就绪状态,然后根据线程调度机制竞争获取锁。

  4. 只有获取到对象的锁的线程才能继续执行同步代码块中的内容,而其他未获取到锁的线程仍然处于阻塞状态,直到再次获得锁的机会。

希望大家多多支持!?

文章来源:https://blog.csdn.net/weixin_71841320/article/details/135769700
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。