wait(), notify()和notifyAll()方法用於在線程間創建關聯. 在對象上調用wait()將使線程進入WAITTING狀態, 直到其餘線程對同一個對象調用notify()或notifyAll(). 在任何線程上, 對一個對象調用wait(), notify()和notifyAll(), 都須要先得到這個對象的鎖, 就是說, 這些方法必須在synchronized方法或代碼塊中調用.java
調用notify()時, 在全部WAITING狀態的線程中只會有一個線程被通知, 這個選擇是隨機的, 被通知的線程並不會當即獲得對象的鎖, 而是一直等到調用notify()的線程釋放鎖, 在這以前線程都是BLOCKED狀態. 當得到鎖後, 就會從BLOCKED狀態變爲RUNNING狀態. 例子dom
class Shared { synchronized void waitMethod() { Thread t = Thread.currentThread(); System.out.println(t.getName() + " is releasing the lock and going to wait"); try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(t.getName() + " has been notified and acquired the lock back"); } synchronized void notifyOneThread() { Thread t = Thread.currentThread(); notify(); System.out.println(t.getName() + " has notified one thread waiting for this object lock"); } } public class MainClass { public static void main(String[] args) { final Shared s = new Shared(); //Thread t1 will be waiting for lock of object 's' Thread t1 = new Thread() { @Override public void run() { s.waitMethod(); } }; t1.start(); //Thread t2 will be waiting for lock of object 's' Thread t2 = new Thread() { @Override public void run() { s.waitMethod(); } }; t2.start(); //Thread t3 will be waiting for lock of object 's' Thread t3 = new Thread() { @Override public void run() { s.waitMethod(); } }; t3.start(); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } //Thread t4 will notify only one thread which is waiting for lock of object 's' Thread t4 = new Thread() { @Override public void run() { s.notifyOneThread(); } }; t4.start(); } }
.ide
當線程在對象上調用notifyAll()時, 全部WAITING狀態的線程都會被通知, 全部的線程都會從WAITING狀態變成BLOCKED狀態, 而後爭搶對象的鎖. 獲得對象鎖的線程, 將變成RUNNING狀態, 而其餘線程則繼續保持BLOCKED狀態繼續等待獲取對象鎖. 例子ui
class Shared { synchronized void waitMethod() { Thread t = Thread.currentThread(); System.out.println(t.getName() + " is releasing the lock and going to wait"); try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(t.getName() + " has been notified and acquired the lock back"); } synchronized void notifyAllThread() { Thread t = Thread.currentThread(); notifyAll(); System.out.println(t.getName() + " has notified all threads waiting for this object lock"); } } public class MainClass { public static void main(String[] args) { final Shared s = new Shared(); //Thread t1 will be waiting for lock of object 's' Thread t1 = new Thread() { @Override public void run() { s.waitMethod(); } }; t1.start(); //Thread t2 will be waiting for lock of object 's' Thread t2 = new Thread() { @Override public void run() { s.waitMethod(); } }; t2.start(); //Thread t3 will be waiting for lock of object 's' Thread t3 = new Thread() { @Override public void run() { s.waitMethod(); } }; t3.start(); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } //Thread t4 will notify all threads which are waiting for lock of object 's' Thread t4 = new Thread() { @Override public void run() { s.notifyAllThread(); } }; t4.start(); } }
.this
一個生產者和消費者的例子spa
注意, 在1個生產1個消費的狀況下, 是能確保生產和消費的互相通知的, 可是在2個生產1個消費的狀況下, 有可能要屢次notify後消費線程才能拿到queue的鎖.線程
public class DemoThreadWait1 { Queue<Integer> queue = new LinkedList<>(); public void consume() { synchronized (queue) { while (queue.isEmpty()) { try { System.out.println("consume wait"); queue.wait(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("remove all"); queue.clear(); queue.notify(); } } } public void produce(int i) { synchronized (queue) { if (queue.size() < 5) { System.out.println("add " + i); queue.add(i); } if (queue.size() >= 5) { queue.notify(); try { System.out.println("produce wait"); queue.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } } } public static void main(String[] args) { DemoThreadWait1 demo = new DemoThreadWait1(); new Thread(()->{ while(true) { demo.consume(); } }).start(); new Thread(()->{ while(true) { demo.produce((int) (Math.random() * 1000)); } }).start(); new Thread(()->{ while(true) { demo.produce((int) (Math.random() * 1000)); } }).start(); } }