wait()/ notify()/ notifyAll()
任何Object对象都可以作为这三个方法的主调,但是不推荐线程对象调用这些方法。
1使用wait()、notify()和notifyAll()时需要首先对调用对象加锁【必须使用在同步代码块】
2调用wait()方法后,线程状态会从RUNNING变为WAITING,并将当线程加入到lock对象的等待队列中【会释放锁】 ,后面的代码就不执行了 。当被唤醒并被执行时,是接着上次执行到的wait()方法代码后面继续往下执行的。
3调用notify()或者notifyAll()方法后,等待在lock对象的等待队列的线程不会马上从wait()方法返回,必须要等到调用notify()或者notifyAll()方法的线程将lock锁释放,等待线程才有机会从等待队列返回。这里只是有机会,因为锁释放后,等待线程会出现竞争,只有竞争到该锁的线程才会从wait()方法返回,其他的线程只能继续等待
下面代码演示
public class WaitNotifyThread { //条件是否满足的标志 private static boolean flag = true; //对象的监视器锁 private static Object lock = new Object(); public static void main(String[] args){ Thread waitThread = new Thread(new WaitThread(),"WaitThread"); waitThread.start(); Thread notifyThread = new Thread(new NotifyThread(),"NotifyThread"); notifyThread.start(); } /** * 等待线程 */ private static class WaitThread implements Runnable{ public void run() { //加锁,持有对象的监视器锁 synchronized (lock){ //只有成功获取对象的监视器才能进入这里 //当条件不满足的时候,继续wait,直到某个线程执行了通知 //并且释放了lock的监视器(简单来说就是锁)才能从wait //方法返回 while (flag){ try { System.out.println(Thread.currentThread().getName() + " flag is true" ); lock.wait(); //相当于睡眠 但是释放锁的 } catch (InterruptedException e) { e.printStackTrace(); } } //条件满足,继续工作 System.out.println(Thread.currentThread().getName() + " flag is false " ); } } } /** * 通知线程 */ private static class NotifyThread implements Runnable{ public void run() { synchronized (lock){ //获取lock锁,然后执行通知,通知的时候不会释放lock锁 //只有当前线程退出了lock后,waitThread才有可能从wait返回 System.out.println(Thread.currentThread().getName() + " holds lock " ); lock.notifyAll(); //唤醒wait 但是只有释放代码块以后 wait变成就绪 flag = false; try { Thread.sleep(1000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } //再次加锁 synchronized (lock){ System.out.println(Thread.currentThread().getName() + " holds lock again " ); try { Thread.sleep(1000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } }
运行结果会有两种
或者
这个例子只是想说明 调用notify 或者notifyAll 并不会释放锁 要等到同步代码执行完成以后 才会释放 释放以后,两个线程的执行是不确定的
所以会有2个结果