时间:2021-05-20
Java 中Object的wait() notify() notifyAll()方法使用
一、前言
对于并发编程而言,除了Thread以外,对Object对象的wati和notify对象也应该深入了解其用法,虽然知识点不多。
二、线程安全基本知识
首先应该记住以下基本点,先背下来也无妨:
同一时间一个锁只能被一个线程持有 调用对象的wait()和notify()前必须持有它
三、wait()和notify()理解
3.1 wait()和notify()方法简介
wait()和notify()都是Object的方法,可以认为任意一个Object都是一种资源(或者资源的一个代表),当多个线程对一个资源进行操作时,如果线程发现这个资源还没有准备好,它就可以在这个资源上进行等待,即调用这个资源的wait()方法,如果有另外的线程经过某些处理觉得这个资源可用了,会调用这个这个资源的notify()方法,告诉等待它的线程,这个资源可以用了。
当然不使用wait()和notify()方法也是可以的,可以用while()死循环来判断,如下面的伪代码:
class Resource{ static boolean canUse=false;}while(!Resource.canUse){ //如果不可用,死循环在这里等待}//当资源可以使用后,就会跳出循环,往下执行这样做是可以,但是特别消耗CPU资源,所以建议用户使用wait()和notify()方法。
3.2 wait()和notify()的价值
其实从单词意思来看就能看出来,wait就是等待,说明这个资源没有准备好,我要等,还有这一个wait(long timeout) ,表示我只能等待你这么长时间了,过时不候啊,而调用notify()的线程肯定就是对资源进行处理的,处理完进行通知。所以呢,它们就经常用在生产者和消费者模式中。任何涉及等资源到来的情景都适合用这两个方法,
3.3 为什么wait()和notify()必须和synchronized一起使用
当不在synchronized同步块中使用wait()和notify()或者调用方法的对象不是synchronized的同步锁就会抛异常:
java.lang.IllegalMonitorStateException很多人会疑惑为什么必须持有这个对象的锁才能调用对象的wait()和notify()方法呢,我也有这个疑惑,而且我认为这么做是没有必要的。首先看下面的代码:
public class WaitTest{ // 这是一个资源,模拟的Object final NoObjct resource=new NoObjct(); public static void main(String[] args) throws Exception{ WaitTest d=new WaitTest(); d.test(); } public void test() throws Exception{ Runnable r=new Runnable(){ public void run(){ // 调用资源的模拟的wait方法,在方法内部使用synchronized resource.noWait(); System.out.println('线程等待完,执行'); } }; Thread t=new Thread(r); t.start(); Thread.sleep(2000); System.out.println('准备唤醒等待资源的线程'); // 调用资源的模拟的notify方法,在方法内部使用synchronized resource.noNotify(); }}// 因wait()和notify()是final方法,不能覆盖,所以模拟一个Object对象class NoObjct{ // 模拟wait方法 public void noWait(){ // 这个就相当于将synchronized放到wait方法内部 synchronized(this){ try{ this.wait(); }catch(InterruptedException e){ e.printStackTrace(); } } } // 模拟notify方法 public void noNotify(){ // 这个就相当于将synchronized放到notify方法内部 synchronized(this){ this.notify(); } }}这是一个简单的wait()和notify()例子,wait等待,notify唤醒。如果忽略掉模拟的Object会发现代码简洁了许多,否则就要每次使用synchronized,如下代码:
public class WaitTest{ // 这是一个资源,模拟的Object final Object resource=new Object(); public static void main(String[] args) throws Exception{ WaitTest d=new WaitTest(); d.test(); } public void test() throws Exception{ Runnable r=new Runnable(){ public void run(){ // 必须使用synchronized try{ synchronized(resource){ resource.wait(); } }catch(InterruptedException e){ e.printStackTrace(); } System.out.println('线程等待完,执行'); } }; Thread t=new Thread(r); t.start(); Thread.sleep(2000); System.out.println('准备唤醒等待资源的线程'); // 必须使用synchronized synchronized(resource){ resource.notify(); } }}所以呢,我觉得wait()和notify()和synchronized一起没有什么意义,毕竟synchronized用来进行代码同步的,和线程之间唤醒没有什么关系(希望有读者能给我相反的意见并说服我)。但是既然这么规定了就必须要去遵守,即必须在synchronized中使用wait和notify,且调用方法的对象必须是同步对象。
四、何时使用wait()和notify()
在上面已经说了这两个方法的其中一个价值就是用在生产者和消费者模式。但是通过使用它们来构建的生产者和消费者模型很低级而且复杂,完全可以使用BlockingQueue接口的实现类来构建。比如可以使用ArrayBlockingQueue,它既能保证线程安全又能实现阻塞效果,何乐而不为呢。
除此之外就只有线程间休眠与唤醒了。
感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!
声明:本页内容来源网络,仅供用户参考;我单位不保证亦不表示资料全面及准确无误,也不保证亦不表示这些资料为最新信息,如因任何原因,本网内容或者用户因倚赖本网内容造成任何损失或损害,我单位将不会负任何法律责任。如涉及版权问题,请提交至online#300.cn邮箱联系删除。
wait(),notify(),notifyAll()等方法介绍在Object.java中,定义了wait(),notify()和notifyAll()等接口。
wait(),notify()和notifyAll()都是java.lang.Object的方法:wait():Causesthecurrentthreadto
Java中的wait/notify/notifyAll可用来实现线程间通信,是Object类的方法,这三个方法都是native方法,是平台相关的,常用来实现生产
wait(),notify(),notifyAll()不属于Thread类,而是属于Object基础类,也就是说每个对象都有wait(),notify(),no
wait、notify和notifyAll方法是Object类的finalnative方法。所以这些方法不能被子类重写,Object类是所有类的超类,因此在程序