扫码关注公众号

java语言考点之wait、notify和notifyAll
09-19
301观看
01

wait()和sleep()的区别

sleep来自Thread类,和wait来自Object类调用sleep()方法的过程中,线程不会释放对象锁。而调用wait方法线程会释放对

来自:并发和同步-wait()、notify()和notifyAll()
02

Notify和notifyAll的区别(阿里面试题)

 由图可知。进入等待队列后,会由notify或notifyAll唤醒 当你调用notify时,只有一个等待线程会被唤醒而且它不能保证哪个线程会被唤醒,这取决于线程调度器。虽然如果你调用notifyAll方法,那么等待该锁的所有线程都会被唤醒,但是在执行剩余的代码之前,所有被唤醒的线程都将争夺锁定,这就是为什么在循环上调用wait,因为如果多个线程被唤醒,那么线程是将获得锁定将首先执行,它可能会重置等待条件,这将迫使后续线程等待。因此,notify和notifyAll之间的关键区别在于notify()只会唤醒一个线程,而notifyAll方法将唤醒所有线程。

来自:并发和同步-wait()、notify()和notifyAll()
03

为什么 wait(), notify()和 notifyAll()必须在同步方法或者同步块中被调用?

Java中,任何对象都可以作为锁,并且wait(),notify()等方法用于等待对象的锁或者唤醒线程,在Java的线程中并没有可供任何对象使用的锁,所以任意对象调用方法一定定义在Object类中。wait(),notify()和notifyAll()这些方法在同步代码块中调用有的人会说,既然是线程放弃对象锁,那也可以把wait()定义在Thread类里面啊,新定义的线程继承于Thread类,也不需要重新定义wait()方法的实现。然而,这样做有一个非常大的问题,一个线程完全可以持有很多锁,你一个线程放弃锁的时候,到底要放弃哪个锁?当然了,这种设计并不是不能实现,只是管理起来更加复杂。综上所述,wait()、notify()和notifyAll()方法要定义在Object类中。

来自:并发和同步-wait()、notify()和notifyAll()
04

wait/notify会带来哪些问题?

1.过早唤醒问题等待线程W和通知线程N都为同步对象someObject锁线程,如果通知线程N3更新好了共享变量,调用notifyall通知唤醒所有someObject等待集的等待线程,但是等待线程W1、W2发现其保护条件并没有成立,这就使得该线程被唤醒之后仍然需要继续等待,这种等待线程在其所需的保护条件并未成立的情况下被唤醒的现象就被称为过早唤醒造成资源浪费。2.信号丢失问题3.欺骗性唤醒问题4.上下文切换问题首先,等待线程执行Object.wait()至少会导致该线程对相应对象内部锁的两次申请与释放。通知线程在执行Object.notify()/notifyAll()时需要持有相应对象的内部锁,因此Object.notify()/notifyAll()调用会导致一次锁的申请。而锁的申请与释放可能导致上下文切换。其次,等待线程从被暂停到唤醒这个过程本身就会导致上下文切换。再次,被唤醒的等待线程在继续运行时需要再次申请相应对象的内部锁,此时等待线程可能需要和相应对象的人口集中的其他线程以及其他新来的活跃线程(即申请相应的内部锁且处于RUNNABLE状态的钱程)争用相应的内部锁,而这又可能导致上下文切换。

来自:并发和同步-wait()、notify()和notifyAll()
课程
专栏
java语言-并发和同步-wait()、notify()和notifyAll()
3专栏
1课程
4 试题