wait()和notify()

不使用等待/通知机制实现线程间的通信
不使用等待/通知机制实现线程间的通信的话就使用不停地通过while语句轮询机制来检测某一个
条件,这样会浪费CPU资源。如果轮询的时间间隔很小,更浪费CPU资源;如果轮询的时间间隔
很大,有可能会取不到想要的数据。所以就需要有一种机制来实现减少CPU的资源浪费,而且还
可以实现在多个线程间通信,就是“wait/notify”机制。
等待/通知机制的实现:

wait

方法wait()的作用是使当前执行代码的线程进行等待,wait()方法是Object类的方法,该方
法用来将当前线程置入“预知性队列”中,并且在wait()所在的代码行处停止执行,直到接到通
知或被中断为止。在调用wait()之前,线程必须获得该对象的对象级别锁,即只能在同步方法
或者同步代码块中调用wait()方法。执行wait()方法之后,当前线程释放锁。在从wait()返
回之前,线程与其他线程竞争重新获得锁。如果调用wait()时没有持有适当的锁,则抛出
IllegalMoitorStateException,他是RuntimeException的一个子类,因此,不需要try-catch语句进
行捕捉异常。

notify

方法notify()也要在同步方法或同步代码块中调用,即在调用前,线程也必须获得该对象的对象
级锁。如果调用notify()时没有持有适当的锁,也会抛出IllegalMonitorStateException。该方法
用来通知那些可能等待该对象的对象锁的其他线程,如果有多个线程等待,则由线程规划器随即
挑选出其中一个呈wait状态的线程,对其发起通知notify,并使他等待获取该对象的对象锁。需要
说明的是,在执行notify()方法后,当前线程不会马上释放该对象的锁,呈wait状态的线程也并
不能马上获取该对象锁,要等到执行notify()方法的线程将程序执行完,也就是退出
synchronized代码块之后,当前线程才会释放锁,而程wait状态所在的线程次可以获取该对象
锁。当第一个获得了该对象锁的wait线程运行完毕后,他会释放掉该对象锁,此时如果该对象没
有再次使用notify语句,则即便该对象已经空闲,其他wait状态等待的线程由于没有得到该对象的
通知,还会继续阻塞在wait状态,直到这个对象发出一个notify或notifyAll。

总结

总结一下就是:wait使线程停止运行,而notify使停止的线程继续运行。
wait()方法可以使调用该方法的线程释放共享资源的锁,然后从运行状态退出,进入等待队列,直到再次被唤醒。
notify()方法可以随机唤醒等待队列中等待同一共享资源的“一个”线程,并使该线程退出等待队列,进入可运行方法,也就是notify()方法仅通知“一个”线程。
notifyAll()方法可以使所有正在等待队列中等待同一资源的“全部”线程从等待状态退出,进入可运行状态。此时,优先级高的那个线程最先执行,但也有可能是随机执行。

线程的几种状态

新建状态(New):
用new语句创建的线程处于新建状态,此时它和其他Java对象一样,仅仅在堆区中被分配了内存。
就绪状态(Runnable):
当一个线程对象创建后,其他线程调用它的start()方法,该线程就进入就绪状态,Java虚拟机会为它创建方法调用栈和程序计数器。处于这个状态的线程位于可运行池中,等待获得CPU的使用权。
运行状态(Running):
处于这个状态的线程占用CPU,执行程序代码。只有处于就绪状态的线程才有机会转到运行状态。
阻塞状态(Blocked):
阻塞状态是指线程因为某些原因放弃CPU,暂时停止运行。当线程处于阻塞状态时,Java虚拟机不会给线程分配CPU。直到线程重新进入就绪状态,它才有机会转到运行状态。
阻塞状态可分为以下3种:
*位于对象等待池中的阻塞状态(Blocked in object’s wait pool):
当线程处于运行状态时,如果执行了某个对象的wait()方法,Java虚拟机就会把线程放到这个对象的等待池中,这涉及到“线程通信”的内容。
*位于对象锁池中的阻塞状态(Blocked in object’s lock pool):
当线程处于运行状态时,试图获得某个对象的同步锁时,如果该对象的同步锁已经被其他线程占用,Java虚拟机就会把这个线程放到这个对象的锁池中,这涉及到“线程同步”的内容。
*其他阻塞状态(Otherwise Blocked):
当前线程执行了sleep()方法,或者调用了其他线程的join()方法,或者发出了I/O请求时,就会进入这个状态。
死亡状态(Dead):
当线程退出run()方法时,就进入死亡状态,该线程结束生命周期。
当方法wait()被执行后,锁资源自动释放,但执行完notify()方法,锁却不自动释放。
当线程呈wait状态时,调用线程对象的interrupt()方法会出现InterruptedException异常。
调用notify()一次只通知一个线程进行唤醒。

方法wait(long)的使用:

带一个参数的wait(long)方法的功能是等待某一时间内是否有线程对所进行唤醒,如果超过这
个时间则自动唤醒。
等待wait的条件发生变化:
if被while替代是有原因的:比如有个线程进方法了,发现条件不满足,就wait,
然后再次被唤醒的时候,不会进行二次判断的,而是直接向前走!
使用while则不一样,每次都会判断,不满足条件就继续等待!
生产者/消费者模式实现:
等待/通知模式是最经典的案例就是“生产者/消费者模式”。但是在此模式在使用上有几种“变形”,
还有一些小的注意事项,但原理都是基于wait/notify的。

你可能感兴趣的:(java,wait,notify,多线程)