wait讲解

简介: wait讲解

开始正题之前,我们要先进行一点知识点的补充


上一期我们更新了一期关于线程安全的知识,对于volatile在这里在做出一些补充


有些文章上说线程修改一个变量的时候,从主内存读取到工作内存上,在工作内存上修改完以后再返回主内存


由于t1线程频繁从主内存读取数据,且值一样,所以编译器做了优化,让t1读取工作内存,


t2修改主内存的值,t1只读工作内存,所以修改无效


这里的主内存指的是内存,工作内存指的是CPU寄存器+缓存


在Java官方文档中使用主内存和工作内存这样的语言


因为Java的特点就是跨平台语言,兼容多种操作系统,兼容多种硬件设备,特别是CPU


CPU的种类有很多,现在的CPU上面还有缓存.缓存是CPU内部存储数据的空间


现在市面上的CPU有L1,L2,L3三级缓存


读取缓存的速度介于寄存器和内存之间


读取寄存器的速度比内存快3-4个数量级


当CPU想要读取一个内存数据的时候,过程是这样的


1.看看CPU寄存器有吗


2没有,看L1有吗


3没有,看L2有吗


4没有,看L3有吗


5还没有,看内存有吗


当这个流程中的某一个结构读到了数据,就结束读取


OK,言归正传,上面的知识就是解释了一下主内存和工作内存


下面开始今天的正题

                                    目录

                                 🚀1.wait和notify的介绍

      🚀2.代码举例

                      🚀3.wait和sleep的区别及联系

1.wait和notify的介绍

多线程的调度是随机的,但是在某些情况下我们也希望代码有序,之前学过的join保证了有序,

今天我们就再来学习一个方法,也能保证代码的执行顺序

wait就是让某个线程停下来先等一等,notify就是唤醒这个线程,继续执行

我们举一个例子

举一个取钱的例子

ATM机上取钱的例子

d1d2b8f3a98d486cbe07afa6f87b9c89.png

现在1号滑稽要取钱,但是机子里没有钱,他就只能出来,然后过了一会,1号滑稽又进去了,他这样频繁的进出,让其他线程没有机会上CPU调度,这一现象称为线程饿死


为了解决这个局面,我们让1号滑稽老铁先阻塞等待一会,让2,3,4去执行


这个时候我们使用wait,进行阻塞等待,此时,当银行工作人员来了以后,充了钱,这时让1号滑稽去进行取钱操作,这一过程要用到notify,进行唤醒wait的操作


2.代码举例

现在写一个具体的代码来分析分析

1

public class ThreadDemo15 {
    public static void main(String[] args) throws InterruptedException {
        Object object = new Object();
        System.out.println("wait 之前");
        synchronized (object) {
            object.wait();
        }
        System.out.println("wait 之后");
    }
}


e896337715e842c89b8f46d614cbf725.png

可以看到运行结果不符合预期,这是因为没有唤醒,所以就一直等待了,我们再写一个带唤醒操作版本的


public class ThreadDemo16 {
    public static void main(String[] args) throws InterruptedException {
        Object locker = new Object();
        Thread t1 = new Thread(() -> {
            try {
                System.out.println("wait 开始");
                synchronized (locker) {
                    locker.wait();
                }
                System.out.println("wait 结束");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        t1.start();
        Thread.sleep(1000);
        Thread t2 = new Thread(() -> {
            synchronized (locker) {
                System.out.println("notify 开始");
                locker.notify();
                System.out.println("notify 结束");
            }
        });
        t2.start();
    }
}


t1线程在打印完wait开始后就进入了阻塞等待,然后t2开始执行,执行到了notify就要唤醒t1线程,但是由于notify操作在锁里,所以只有当t2线程释放锁以后,t1才可以开始执行

所以执行结果是


1590e4bac8b44196b52e2652ec5173e9.png


注意,wait和notify操作都必须在synchronized操作下执行

且wait和notify以及synchronized的操作对象必须是同一个

wait必须先执行,才能执行notify,如果先执行notify,那么唤醒无效,唤醒了个寂寞啊

wait主要功能

1.解锁

2.阻塞等待(此时t1的锁给了t2)

3.收到通知,唤醒线程,重新获取锁 (t2释放了锁)

wait必须写到synchronized里面


这个代码执行顺序,是t1先执行,但是我们通过wait和notify操作,控制了执行顺序


1.t1先执行一会


2.然后让t2执行一会


3.再让t1执行


唤醒操作


notify方法只是唤醒某一个等待线程.


使用notifyAll方法可以一次唤醒所有的等待线程.


如果t1,t2,t3等待的都是同一个对象,那么在主函数中唤醒,就只是唤醒其中一个,如果调用notifyAll,那么三个线程都会唤醒,然后抢占锁,依次执行


3.下面来想一想wait和sleep的区别和联系

联系

1.wait有个带参数的版本,用来体现超时时间,和sleep差不多,sleep也是有时间参数的


2.他们两个都能提前唤醒,sleep通过interrupt唤醒,而wait通过notify唤醒


区别


初心不同


wait:为了控制代码执行顺序


sleep:单纯让线程休眠一会


实现方式不同


wait要在加锁条件下使用,sleep没有限制条件


wait被调用后当前线程进入waiting状态并释放锁,并可以通过notify和notifyAll方法进行唤醒;sleep被调用后当前线程进入TIMED_WAIT状态,不涉及锁相关的操作;


起源不同:


wait是Object类中的一个方法,sleep是Thread类中的一个方法;


讲到现在,wait也就差不多介绍到这里


今天的内容就讲到这里,我们下期再见!!!

4a120fb9ad2149e9b1e501150a94833e.jpg

相关文章
|
1月前
|
Java
理解wait()、notify()和notifyAll()
【10月更文挑战第9天】
|
6月前
|
弹性计算 运维 Shell
wait命令
【4月更文挑战第29天】
47 2
|
6月前
|
API
wait-nofity
wait-nofity
41 0
sleep () 和 wait () 的区别
sleep () 和 wait () 的区别
86 0
|
Java 程序员
sleep 和 wait 的区别
Java 中,线程的 "sleep" 和 "wait" 方法区别
129 0
|
监控
实践解读CLOSE_WAIT和TIME_WAIT
实践解读CLOSE_WAIT和TIME_WAIT
389 0
实践解读CLOSE_WAIT和TIME_WAIT
线程 - wait & sleep 区别
线程 - wait & sleep 区别
119 0
|
Java
sleep与wait区别
第一个区别是在对系统资源的占用上。 wait是Object类的一个函数(也就意味着所有对象都有这个函数),指线程处于进入等待状态,此时线程不占用任何资源,不增加时间限制。wait可以被notify和notifyAll函数唤醒(当然这两个同时也是Object的函数)。 而sleep则是Thread类的一个函数,指线程被调用时,占着CPU不工作。此时,系统的CPU部分资源被占用,其他线程无法进入,会增加时间限制。
141 0
|
监控
sleep 与 wait 区别
sleep 与 wait 区别
114 0