等待 通知机制 - morris131/morris-book GitHub Wiki

##等待-通知机制

等待-通知机制原理

等待/通知机制,是指一个线程A调用了对象O的wait()方法进入等待状态,而另一个线程B 调用了对象O的notify()或者notifyAll()方法,线程A收到通知后从对象O的wait()方法返回,进而 执行后续操作。上述两个线程通过对象O来完成交互,而对象上的wait()和notify/notifyAll()的 关系就如同开关信号一样,用来完成等待方和通知方之间的交互工作。

等待-通知机制的实现

package com.morris.ch3;

public class WaitNotifyThread {
	
	final static Object object = new Object();
	
	static boolean flag = true;
	
	public static void main(String[] args) throws InterruptedException {
		new WaitThread().start();
		Thread.sleep(1000);
		new NotifyThread().start();
	}
	
	static class WaitThread extends Thread {
		@Override
		public void run() {
			synchronized (object) {
				while(flag) {
					try {
						System.out.println("WaitThread is waiting...");
						object.wait();
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
				System.out.println("WaitThread is stop.");
			}
		}
	}
	
	static class NotifyThread extends Thread {
		@Override
		public void run() {
			synchronized (object) {
				System.out.println("NotifyThread is notifyAll.");
				object.notifyAll();
				flag = false;
			}
		}
	}
	

}

调用wait()、notify()以及notifyAll()时需要注意的细节,如下。

  1. 使用wait()、notify()和notifyAll()时需要先对调用对象加锁。
  2. 调用wait()方法后,线程状态由RUNNING变为WAITING,并将当前线程放置到对象的等待队列。
  3. notify()或notifyAll()方法调用后,等待线程依旧不会从wait()返回,需要调用notify()或notifAll()的线程释放锁之后,等待线程才有机会从wait()返回。
  4. notify()方法将等待队列中的一个等待线程从等待队列中移到同步队列中,而notifyAll()方法则是将等待队列中所有的线程全部移到同步队列,被移动的线程状态由WAITING变为BLOCKED。
  5. 从wait()方法返回的前提是获得了调用对象的锁。

从上述细节中可以看到,等待/通知机制依托于同步机制,其目的就是确保等待线程从wait()方法返回时能够感知到通知线程对变量做出的修改。

notify随机通知一个线程

调用notify()方法一次只随机通知一个线程进行唤醒。

package com.morris.ch3;

public class NotifyTest {
	
	static Object object = new Object();
	
	public static void main(String[] args) throws InterruptedException {
		new WaitThread("wait1").start();
		new WaitThread("wait2").start();
		WaitThread.sleep(1000);
		new NotifyThread().start();
	}
	
	static class WaitThread extends Thread {
		
		WaitThread(String name) {
			super(name);
		}
		
		@Override
		public void run() {
			synchronized (object) {
				try {
					System.out.println(Thread.currentThread().getName() + " is waiting");
					object.wait();
					System.out.println(Thread.currentThread().getName() + " is stop");
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}
	}
	
	static class NotifyThread extends Thread {
		@Override
		public void run() {
			System.out.println("notity one thread");
			synchronized (object) {
				object.notify();
				object.notify();
			}
		}
	}

}

notifyAll唤醒所有线程

package com.morris.ch3;

public class NotifyAllTest {
	
	static Object object = new Object();

	public static void main(String[] args) throws InterruptedException {
		new WaitThread("wait1").start();
		new WaitThread("wait2").start();
		WaitThread.sleep(1000);
		new NotifyThread().start();
	}

	static class WaitThread extends Thread {

		WaitThread(String name) {
			super(name);
		}

		@Override
		public void run() {
			synchronized (object) {
				try {
					System.out.println(Thread.currentThread().getName() + " is waiting");
					object.wait();
					System.out.println(Thread.currentThread().getName() + " is stop");
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}
	}

	static class NotifyThread extends Thread {
		@Override
		public void run() {
			System.out.println("notity one thread");
			synchronized (object) {
				object.notifyAll();
			}
		}
	}

}

wait(long)的使用

等待某一时间段是否有线程对锁进行唤醒,如果超过这个时间则自动唤醒。

package com.morris.ch3;

public class WaitSometimeTest {
	
static Object object = new Object();
	
	public static void main(String[] args) throws InterruptedException {
		new WaitThread().start();
	}
	
	static class WaitThread extends Thread {
		
		@Override
		public void run() {
			synchronized (object) {
				try {
					System.out.println(Thread.currentThread().getName() + " is waiting");
					object.wait(1000);
					System.out.println(Thread.currentThread().getName() + " is stop");
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}
	}

}

面试题:交替打印ABAB

package com.morris.ch3;

public class WaitNofityTest {

	private static Object lock = new Object();

	private static volatile boolean isA = true;

	public static void main(String[] args) {
		for (int i = 0; i < 10; i++) {
			new A("A" + i).start();
			new B("B" + i).start();
		}
	}

	static class A extends Thread {

		A(String name) {
			super(name);
		}

		@Override
		public void run() {
			synchronized (lock) {
				while (true) {
					if (isA) {
						System.out.println(Thread.currentThread().getName() + ": A");
						isA = false;
						lock.notifyAll();
						break;
					} else {
						try {
							lock.wait();
						} catch (InterruptedException e) {
							e.printStackTrace();
						}
					}
				}
			}
		}
	}

	static class B extends Thread {

		B(String name) {
			super(name);
		}

		@Override
		public void run() {
			synchronized (lock) {
				while (true) {
					if (isA) {
						try {
							lock.wait();
						} catch (InterruptedException e) {
							e.printStackTrace();
						}
					} else {
						System.out.println(Thread.currentThread().getName() + ": B");
						isA = true;
						lock.notifyAll();
						break;
					}
				}
			}
		}
	}

}
⚠️ **GitHub.com Fallback** ⚠️