java.lang.Objectjava
public final native void wait() throws InterruptedException; public final native void wait(long millis, int nanos) throws InterruptedException; public final void wait(long millis) throws InterruptedException { wait(millis, 0); } public final native void notify(); public final native void notifyAll();
wait():使调用该方法的线程释放锁,从运行状态退出,进入等待队列,直到被唤醒。spa
wait(long timeout):等待一段时间是否有线程唤醒锁,若是没有,超时自动唤醒。线程
wait(long timeout, int nanos):等待唤醒时间纳秒级别。code
notify():随机唤醒等待队列中的等待同一个锁的一个线程,使这个线程退出等待队列,进入可运行状态。对象
notifyAll():唤醒全部等待一样锁的全部线程,从等待队列中退出,进入可运行状态。队列
每一个对象都有个monitor,初始是0,执行完synchronized值就是1。ip
wait/notify须要在得到monitor的线程中才能够执行。资源
因此,wait/notify须要在synchronized中执行。同步
其中,wait又会释放掉锁,破坏掉同步。it
synchronized代码块生成的字节码,被monitorenter
和monitorexit
包围,持有对象的monitor;
线程执行wait/notify方法时,必须持有对象的monitor;
因此,wait/notify方法在synchronized同步块中执行,就持有了对象的锁。
Java语言的同步机制在底层实现上只有两种方式:互斥和协同。
互斥:即synchronized内置锁。
协同:即内置条件队列,wait/notify/notifyAll。
条件队列中是处于等待状态的线程,等待特定条件为真。每一个Java对象均可以做为一个锁,一样每一个Java对象均可以做为一个条件队列。经过wait/notify/notifyAll来操做条件队列。
能够理解为:有一个队列,o.wait()就push进去,o.notify()就pull出来。
要调用条件队列的任何一个方法,都必需要得到对象上的锁。
线程是用来工做的,不该该处于等待状态,处于等待状态的条件队列中的线程,必定是执行不下去的。
while(condition is not true) { lock.wait() }
解释:两个消费者线程c1和c2,逻辑都是,判断资源是否为空,是就wait,否就消费一个;某个时刻,两个线程都进入等待队列,而后生产者生产了一个资源,并执行notifyAll,唤醒c1和c2都进入锁池,c1先获取锁,执行完消费掉资源,而后释放锁,此时,若是c2得到锁,若是是if逻辑,那么就会进入消费代码,可是资源已经被c1消费掉了,可能抛出异常。若是是while逻辑,则不会进入消费代码,而是继续等待。
在通常状况下,总应该调用notifyAll唤醒全部须要被唤醒的线程。可能会唤醒其余一些线程,但这不影响程序的正确性,这些线程醒来以后,会检查他们正在等待的条件(循环检测),若是发现条件不知足,就会继续等待
显示锁:Lock,对应内置锁synchronized
显示条件队列:Condition,对应内置条件队列,对应方法是await, signal, signalAll