线程之间的通信

在这里插入图片描述等待分无限等待计时等待

在这里插入图片描述在这里插入图片描述在这里插入图片描述举个例子
我有两个线程 l 和 r
l 线程负责 数据的清洗, r线程是负责数据的处理
在还没有数据清理之前,是不能进行处理的
我可以让 r线程处于无限等待的状态,也就是说当 l线程数据清理完的时候要唤醒 r线程 也就是调用 notify或者 notifyAll 方法,让r线程处理接下来的事务,这就是线程之间的通信

wait 方法会让线程处于等待状态,其实就是将线程临时存储于线程池中
notify 会唤醒线程池中的任意一个等待线程
notifyAll 会唤醒线程池中所有的等待线程

wait: 当前线程必须拥有此对象监视器,等同于当线程必须要有一个锁,
比如说 对象监视器是 Object obj = new Object(); , 那么同步代码块里面使用,必须要 obj.wait() 调用 ,而不是 this.wait() 来调用, 因为对象监视器是 obj,而不是 this , 如果是 this.wait() 调用,那么 synchonized 关键字写法是 synchonized(this) {}, 然后 wait在代码块里面调用

注意了:
sleep方法和 wait 方法的区别
对于sleep()方法,我们首先要知道该方法是属于Thread类中的。而wait()方法,则是属于Object类中的。
我们调用 sleep方法 ,是要加 try/catch 或者 throw的
sleep()方法导致了程序暂停执行指定的时间,让出cpu该其他线程,但是他的监控状态依然保持者,当指定的时间到了又会自动恢复运行状态。

在调用sleep()方法的过程中,线程不会释放对象锁。

而当调用wait()方法的时候,线程会放弃对象锁,进入等待此对象的等待锁定池,只有针对此线程对象调用notify()方法后本线程才进入对象锁定池准备获取对象锁进入运行状态。

注意点二:

让线程停下来等待,可以通过Thread类的静态方法,Thread.sleep(millis);
也可以使用Object及其子类都具备的wait()/wait(millis)方法;两者的异同在下面展开 二、Thread.sleep() 和
Object.wait()的区别

  1. 调用Thread.sleep(),当前线程不释放锁,睡眠过程中一直持有锁对象,睡眠时间过后继续执行;
    2.调用wait()方法,线程释放锁对象,直到这个锁对象的notify或者notifyAll()被调用,才会被唤醒,重新争夺锁。
  2. sleep()是Thread类的静态方法,wait/notify是Object类的通用方法,这也符合Java中锁的理念,对象都可以作为锁。

注意:

  1. wait()方法只能用于同步代码块范围内,且只能对同步方法或者同步代码块持有的锁对象进行wait和notify操作,否则会报错IllegalMonitorStateException,这里再次强调,synchronize 里面使用的对象监视器是 this,就 this.wait() , 如果是 obj什么的,就 obj.wait() 来调用
  2. 两者都可能抛出InterruptedException

———————————————— 版权声明:本文为CSDN博主「muskter」的原创文章,遵循 CC 4.0 BY-SA
版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/muskter/article/details/76064085

也就是说:,sleep方法可以在任何地方使用,

wait方法只能在同步方法和同步代码块中使用

注意sleep方法是单线程的,没有释放锁,这个锁指的是线程锁,不是对象锁,而wait方法释放锁,这个锁是对象锁,所以sleep时间到和wait等到notify之后享受的待遇一样,都是回到就绪状态,等待系统分配cpu

什么是对象锁?
对象锁2
暂时还未掌握的 ReentrantLock
很重要的 ReentrantLock

在执行了notify方法之后,当前线程不会马上释放该对象锁,呈wait状态的线程也不能马上获得该对象锁,
要等到执行notify方法的线程将程序执行完 ,也就是退出sychronized代码块后,当前线程才会释放锁,
而呈wait状态所在的线程才可以获取该对象锁。

执行synchronized代码块的线程首先尝试获取锁,如果失败会先进入ContentionList队列排队等待,线程处于阻塞状态。
为了减少队尾部争用,会把一部分ContentionList中的线程放到EntryList,EntryList中的队头线程去尝试请求锁。
获取锁的线程执行wait会释放锁,线程进入waitSet队列中。
当执行notify时,会把waitSet队头的线程,放在EntryList中,排队等待获取锁。

网上找到了一个很不错的解释
// ProductStack 是一个生产者跟消费者共享的同步机制,这个机制决定了什么情况生产者要wait(),什么情况消费者要wait()
// 可以把ProductStack看作一个产品仓库。当产品仓库满的时候,生产者线程需要wait(),从而放弃对产品仓库的控制。
// 这个时候消费者线程就可以进来了而取得仓库的控制权。一旦消费者消费了产品,那么仓库就不满了。
// 这个时候消费者线程就要notifyAll()生产者线程,让等待的生产者线程唤醒。
// 但是生产者被唤醒后不能马上进行生产,因为它在wait()的时候已经丧失了对仓库的控制权,所以就需要等待消费者线程结束操作,
// 才能重新取得仓库的控制权,再进行生产。
//
// 所以特别注意的是,notifyAll() 并不是让当前线程马上让出控制权而只是让其他wait()当中的线程唤醒而已
// 所以对不起,尽管我唤醒你,可你必须还是要等我用完仓库才能进来。这点必须清楚。
//
// 相反,仓库如果空的时候,消费者线程就会wait(),然后等待生产者线程来生产产品,生产者进程乘虚而入后,让生产者线程生产产品
// 并且唤醒消费者线程。这个情况跟上面就类似了。
//

面试注意点:
1.wait 方法必须在同步方法或同步代码块中使用,即必须要获得一个对象锁,并且要用 notify或notifyAll唤醒
2. sleep和 wait都写在在同步代码块中,线程执行到 sleep方法不会释放锁,(如果释放了锁的话,别的线程过来抢夺执行权,那么你sleep的时间就超了? 这不是很矛盾吗?),

而线程执行到 wait会释放锁,让别的线程过来抢夺这个锁,并且只能有一个线程拥有这个锁,别的线程排队去(那么问题来了,如果我 wait了 ,我不释放锁,别人又怎么获取我的锁并且来唤醒我呢?

再补充一个很形象的解释
wait和notify-> 线程的通信

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值