wait讲解

hello啊,今天为大家带来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机上取钱的例子

 

现在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 之后");
    }
}

 

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

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才可以开始执行

所以执行结果是

注意,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也就差不多介绍到这里

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

               

 

  • 9
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值