在多线程中什么是等待通知机制?
生活总最常见的例子就是上菜系统
1:方法wait()方法作用就是使当前执行代码的线程进行等待,该方法是object类的方法,会使当前线程释放锁。该方法只能在同步方法或则同步块中调用wait()方法。
2:notify()方法也要在同步方法或则同步块中调用,该方法用来通知那些可能等待该对象的对象锁的其他线程,如果有多个线程等待,则有线程规划器随机挑选一个呈wait状态的线程,对其发出通知notify,并使它等待获取该对象的对象锁。在执行notify()方法后,当前线程不会马上释放对象锁,呈wait状态的想爱你成也不会马上获得该对象锁,要等待执行notify()方法的线程将程序执行完,也就是退出synchronized代码块后,当前线程才会释放锁,而wait状态所有的线程才可以获取该对象锁。
public class MyList { private static List list = new ArrayList(); public static void add() { list.add("anyString"); } public static int size() { return list.size(); } }
public class ThreadA extends Thread { private Object lock; public ThreadA(Object lock) { super(); this.lock = lock; } @Override public void run() { try { synchronized (lock) { if (MyList.size() != 5) { System.out.println("wait begin " + System.currentTimeMillis()); lock.wait(); System.out.println("wait end " + System.currentTimeMillis()); } } } catch (InterruptedException e) { e.printStackTrace(); } } }
public class ThreadB extends Thread { private Object lock; public ThreadB(Object lock) { super(); this.lock = lock; } @Override public void run() { try { synchronized (lock) { for (int i = 0; i < 10; i++) { MyList.add(); if (MyList.size() == 5) { lock.notify(); System.out.println("已发出通知!"); } System.out.println("添加了" + (i + 1) + "个元素!"); Thread.sleep(1000); } } } catch (InterruptedException e) { e.printStackTrace(); } }
public static void main(String[] args) { try { Object lock = new Object(); ThreadA a = new ThreadA(lock); a.start(); Thread.sleep(50); ThreadB b = new ThreadB(lock); b.start(); } catch (InterruptedException e) { e.printStackTrace(); } }
下面证明wait()方法释放锁 notify()锁不释放
public class Service { public void testMethod(Object lock) { try { synchronized (lock) { System.out.println("begin wait()"); lock.wait(); System.out.println(" end wait()"); } } catch (InterruptedException e) { e.printStackTrace(); } } }
A B 两个线程同时访问testMethod()方法,但是A进去后释放了锁,导致B也进来,所以打印两次。
public class Service { public void testMethod(Object lock) { try { synchronized (lock) { System.out.println("testMethod() begin wait() ThreadName=" + Thread.currentThread().getName()); lock.wait(); System.out.println("testMethod() end wait() ThreadName=" + Thread.currentThread().getName()); } } catch (InterruptedException e) { e.printStackTrace(); } } public void synNotifyMethod(Object lock) { try { synchronized (lock) { System.out.println("synNotifyMethod() begin notify() ThreadName=" + Thread.currentThread().getName() + " time=" + System.currentTimeMillis()); lock.notify(); Thread.sleep(5000); System.out.println("synNotifyMethod() end notify() ThreadName=" + Thread.currentThread().getName() + " time=" + System.currentTimeMillis()); } } catch (InterruptedException e) { e.printStackTrace(); } } }
public class ThreadA extends Thread { private Object lock; public ThreadA(Object lock) { super(); this.lock = lock; } @Override public void run() { Service service = new Service(); service.testMethod(lock); } }
public class synNotifyMethodThread extends Thread { private Object lock; public synNotifyMethodThread(Object lock) { super(); this.lock = lock; } @Override public void run() { Service service = new Service(); service.synNotifyMethod(lock); } }
public class NotifyThread extends Thread { private Object lock; public NotifyThread(Object lock) { super(); this.lock = lock; } @Override public void run() { Service service = new Service(); service.synNotifyMethod(lock); } }
public static void main(String[] args) throws InterruptedException { Object lock = new Object(); ThreadA a = new ThreadA(lock); a.start(); NotifyThread notifyThread = new NotifyThread(lock); notifyThread.start(); synNotifyMethodThread c = new synNotifyMethodThread(lock); c.start(); }
A线程调用wait()方法释放对象锁,NotifyThread线程唤醒,但是得走完同步方法所以睡眠5s,在这期间不会释放对象锁,
5s过后,释放锁了,A线程再执行完wait()方法后面剩下的代码,这个时候synNotifyMethodThread线程才能进入synNotifyMethod()方法执行。
调用notify()方法一次随机只通知一个线程进行唤醒。
public class Service { public void testMethod(Object lock) { try { synchronized (lock) { System.out.println("begin wait() ThreadName=" + Thread.currentThread().getName()); lock.wait(); System.out.println(" end wait() ThreadName=" + Thread.currentThread().getName()); } } catch (InterruptedException e) { e.printStackTrace(); } } }
public class NotifyThread extends Thread { private Object lock; public NotifyThread(Object lock) { super(); this.lock = lock; } @Override public void run() { synchronized (lock) { lock.notify(); } } }只唤醒了0线程。
修改如下代码
public class NotifyThread extends Thread { private Object lock; public NotifyThread(Object lock) { super(); this.lock = lock; } @Override public void run() { synchronized (lock) { lock.notify(); lock.notify(); lock.notify(); lock.notify(); lock.notify(); lock.notify(); lock.notify(); lock.notify(); lock.notify(); } } }
都唤醒
也可以改成lock.notifyAll();
效果是一样的,唤醒所有的线程。