wait方法简介wait方法的作用是让当前执行代码的线程等待。它是Object类的一个方法。该方法用于将当前线程放入队列中的Wait,并在wait所在的代码行处停止执行,直到收到通知或被中断。该方法只能在同步方法或同步块中调用(即需要先获取对象的监听锁,一般用在synchronized代码块或synchronized修饰的方法中),否则抛出异常IllegalMonitorStateException.A线程中调用Lock对象的wait方法后,Lock对象的监听锁会被释放,A线程会被放入Lock对象的等待队列中,A线程会进入WAITING状态(线程状态查看系列一)。notify/notifyAll方法notify/notifyAll方法的作用是唤醒执行对象等待列表中的一个/所有线程,唤醒它们继续工作。同样,notify/notifyAll方法只能在同步方法或同步块中调用,即线程在调用前也必须获得对象的监视器锁。B线程调用Lock对象的notify/notifyAll方法后,Lock对象等待队列中的A线程从WAITING状态进入BLOCKED状态,而不是直接进入RUNNABLE状态。只有当B线程释放Lock对象的监听锁,A线程拿到后,才进入RUNNABLE状态。所以在编程中,尽量在使用notify/notifyAll()后立即释放对象的monitor锁,让其他线程拿到锁进入RUNNABLE状态。其他注意事项wait、notify/notifyAll方法是Object的本地final方法,不能被覆盖。notify和wait的顺序不能错。如果A线程先执行了notify方法,B线程执行了wait方法,那么B线程就无法被唤醒。详细例子out.println("WaitThread开始执行wait方法");lock.wait();System.out.println("WaitThread被唤醒");}catch(InterruptedExceptione){e.printStackTrace();}}}}publicclassNotifyThreadextendsThread{privateObjectlock;publicNotifyThread(Objectlock){this.lock=lock;}@Overridepublicvoidrun(){System.out.println("NotifyThread开始执行run方法");try{System.out.println("NotifyThread休眠时间为2秒");Thread.sleep(2000);}catch(InterruptedExceptione){e.printStackTrace();}synchronized(lock){System.out.println("NotifyThread开始执行notify方法");lock.notify();try{System.out.println("NotifyThread在执行完notify方法后继续休眠2秒");Thread.sleep(2000);}catch(InterruptedExceptione){e.printStackTrace();}System.out.println("NotifyThread休眠2秒,释放对象监听锁");}}}publicclassMain{publicstaticvoidmain(String[]args){Objectlock=newObject();//创建2个线程WaitThreadwaitThread=newWaitThread(lock);NotifyThreadnotifyThread=newNotifyThread(lock);//启动它们);}}NotifyThread开始执行run方法WaitThread开始执行run方法WaitThread开始执行wait方法NotifyThread休眠2秒NotifyThread开始执行notify方法NotifyThread执行notify方法继续休眠2秒NotifyThread结束2秒的sleep,释放objectmonitorlockWaitThread被唤醒。WaitThread在拿到锁的监听锁后调用wait方法。NotifyThread启动后休眠2秒,保证notify方法在wait方法后面。NotifyThread在执行完notify方法后继续休眠2秒。此时NotifyThread并没有释放Lock的监听锁,所以WaitThread处于BLOCKED状态,并没有真正被唤醒。NotifyThread休眠2秒并释放对象监视器锁。此时NotifyThread获取到Lock监听锁,进入RUNNABLE状态。进阶思考如果线程A获得多个对象的监听锁,然后调用其中一个对象的wait方法,是释放所有对象的锁还是只释放被调用的对象?让我们一起来看一个例子。测试一下。publicclassWaitThreadextendsThread{privateObjectlock;privateObjectother;publicWaitThread(Objectlock,Objectother){this.lock=lock;this.other=other;}@Overridepublicvoidrun(){synchronized(lock){synchronized(other){System.out.println("WaitThread开始执行运行方法");try{System.out.println("WaitThread开始执行wait方法");lock.wait();System.out.println("WaitThread被唤醒");}catch(InterruptedExceptione){e.printStackTrace();}}}}}publicclassNotifyThreadextendsThread{privateObjectlock;privateObjectother;publicNotifyThread(Objectlock,Objectother){this.lock=lock;this.other=other;}@Overridepublicvoidrun(){System.out.println("NotifyThread开始执行run方法");try{System.out.println("NotifyThread睡眠2秒");Thread.sleep(2000);}catch(InterruptedExceptione){e.printStackTrace();}synchronized(lock){System.out.println("NotifyThread获得锁");synchronized(other){System.out.println("NotifyThread获得其他锁");System.out.println("NotifyThread开始执行notify方法");lock.notify();try{System.out.println("NotifyThread执行notify方法后继续休眠2秒");Thread.sleep(2000);}catch(InterruptedExceptione){e.printStackTrace();}System.out.println("NotifyThread休眠2秒并释放对象监视器锁");}}}}publicclassMain{publicstaticvoidmain(String[]args){Objectlock=newObject();Objectother=newObject();//创建2个线程WaitThreadwaitThread=newWaitThread(lock,other);NotifyThreadnotifyThread=newNotifyThread(lock,other);//启动它们waitThread.start();notifyThread.start();}}WaitThread开始执行run方法WaitThread开始执行wait方法NotifyThread开始执行run方法NotifyThread休眠2秒NotifyThread获得锁WaitThread线程获得锁和其他对象锁后,执行wait方法锁。说明wait方法只释放了执行对应的锁,这会导致僵局。因此,如果使用wait和notify机制,一定要确认Wait线程和Notify线程获取了对象锁,尽量避免获取多个对象锁,在某些情况下使用,以防止出现死锁问题。
