[JavaEE]多线程 wait 和 notify

Author:MTingle
major:人工智能

---------------------------------------

Build your hopes like a tower!


目录

文章目录

一、wait 和 notify是什么

二、wait 和 notify 操作

1.wait notify

2.wait 和 sleep 的区别


一、wait 和 notify是什么

wait(等待) notify(通知) 机制,和join用途类似,多个线程之间随机调度,引入wait notify就是为了能够从应用层面上,干预到多个不同线程代码的执行顺序(不会影响线程随机调度的策略),相当于在应用程序代码中,让后执行的线程主动放弃被调度的机会,就可以让先执行的线程先把对应的代码执行完.

二、wait 和 notify 操作

1.wait notify

1.join与wait的不同:join是等待另一个线程执行完才继续执行,wait是等待另一个线程通过notify进行通知,不要求另一个线程必须执行完

2.wait的作用:

1) 释放锁

2) 线程进入阻塞状态,通过 1 和 2 其他进程就有机会拿到锁了(进程进入阻塞,无法打印"wait之后")

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

3) 当其他线程调用notify时,wait解除阻塞,并重新获取到锁

3.调用wait的对象必须和synchronized中的锁对象一致,因此wait解的锁必然是解的object的锁,后续被notify唤醒之后,重新获得的锁就是获取到object的锁(一个对象一把锁,拿到的是之前的锁)

4.如果有其他线程也尝试获取锁,wait被唤醒之后,也要重新参与到锁的竞争中

5.wait 和 sleep join 是一类,都可能会被interrupt提前唤醒

6.wait必须放到synchronized里头使用,因为释放锁的前提是拿到锁

public class ThreadDemo25 {
    public static void main(String[] args) {
        Object locker=new Object();
        Thread t1=new Thread(()->{
           synchronized (locker) {
               System.out.println("t1 wait之前");
               try {
                   locker.wait();
               } catch (InterruptedException e) {
                   throw new RuntimeException(e);
               }
               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) {
                throw new RuntimeException(e);
            }

        });
        t1.start();
        t2.start();
    }
}

理解上述代码的执行过程:

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 notify之后,释放锁, t2 执行完毕, t1 的 wait 就可以获取到锁了,然后执行打印 t1 wait 之后

1) wait的两个版本:

第一个:死等(下策,没有回旋余地)

第二个:带有超时时间的等待,单位是ms,当进入wait的时候,最多等待 timeout ms ,如果这个时间内没有其他线程notify,也不等了(鲁棒性高----容错能力高)

2) wait 和 notify 是通过 object 对象联系起来的

object1.wait()

object2.notify()

此时无法唤醒,两个对象必须一致才能唤醒,notify使用的是哪个对象唤醒的就是哪个对象的wait

3) notifyAll: 唤醒这个对象上所有等待的线程

假设有很多个线程,都使用同一个对象 wait ,针对这个对象进行 notifyAll ,此时所有线程都会被唤醒,这些进程在wait返回时,谁先拿到,谁后拿到是不确定的.相比之下,更倾向于使用notify,notifyAll全部唤醒后不太好控制.

2.wait 和 sleep 的区别

1) wait 提供了一个带有超市时间的版本,sleep也是能指定时间的,都是时间到了就继续执行,解除阻塞

2) wait 和 sleep 都可以被提前唤醒(虽然时间没到,但是也能提前唤醒)  wait 通过 notify 唤醒, sleep 通过 interrupt 唤醒

3) 使用 wait 最主要的目标,一定是不知道要等多少时间的前提下使用的,所谓的 timeout(超时时间)其实是兜底的,使用 sleep ,一定是直到要等多少时间的前提下使用的,虽然能提前唤醒,但是通过异常唤醒,这个操作不应该称为"正常的业务流程",异常唤醒通常是出现一些特殊情况了

4) 不建议完全使用 wait 来代替 sleep ,这种做法虽然可行,但是不被广泛认同,非常少见


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值