一、基本概念
在Java中,任何一個Object對象都有兩個重要的方法:wait()和notify()。這兩個方法被用來實現線程控制和線程之間的通信。wait()方法使當前的線程等待,直到另一個線程調用該對象的notify()方法或notifyAll()方法,從而喚醒該線程;而notify()方法則是喚醒在該對象上等待的線程之一,當有多個線程等待該對象時,notify()方法只會喚醒其中的一個線程。
這裡需要注意的是,wait()和notify()方法必須在一個synchronized塊或者synchronized方法中調用,否則會拋出IllegalMonitorStateException異常。
二、wait()的使用
wait()方法用於使當前線程進入等待狀態,並且釋放該對象的鎖。
public synchronized void add(Object obj) { while (isFull()) { try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } // add the object to the buffer notifyAll(); }
如上面的代碼所示,如果隊列已滿,那麼線程就會進入等待狀態。在等待過程中,線程會釋放該對象的鎖,其他線程可以獲取該鎖並操作該隊列。當其他線程向隊列中添加元素時,會調用notifyAll()方法來喚醒處於等待狀態的線程。
需要注意的是,調用wait()方法後,線程會一直處於等待狀態,直到有其他線程調用notify()或notifyAll()方法才會被喚醒。如果沒有其他線程調用相應的方法,那麼該線程就會一直處於等待狀態,這將導致死鎖。
三、notify()的使用
notify()方法用於喚醒在該對象上等待的線程之一,並且不會釋放該對象的鎖。
public synchronized Object remove() { while (isEmpty()) { try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } // remove an object from the buffer notifyAll(); return obj; }
如上面的代碼所示,如果隊列為空,線程就會進入等待狀態,直到有其他線程向隊列中添加元素時,會調用notifyAll()方法來喚醒處於等待狀態的線程。
需要注意的是,調用notify()方法後,只會喚醒等待隊列中的一個線程,而不是喚醒所有的線程。如果有多個線程等待該對象,那麼喚醒哪個線程是不確定的。
四、wait()和notify()的注意點
1、wait()和notify()必須在synchronized塊或者synchronized方法中調用。
2、wait()方法會使當前線程進入等待狀態,並且釋放該對象的鎖;notify()方法會喚醒在該對象上等待的線程之一,並且不會釋放該對象的鎖。
3、調用wait()方法後,線程會一直處於等待狀態,直到有其他線程調用相應的方法才會被喚醒;調用notify()方法後,只會喚醒等待隊列中的一個線程,而不是喚醒所有的線程。
4、為了避免死鎖,需要在程序中使用notifyAll()方法來喚醒處於等待狀態的所有線程。
五、代碼示例
public class Buffer { private Object[] buffer; private int start = 0; private int end = 0; private int count = 0; public Buffer(int size) { buffer = new Object[size]; } public synchronized void add(Object obj) { while (isFull()) { try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } buffer[end] = obj; end = (end + 1) % buffer.length; count++; notifyAll(); } public synchronized Object remove() { while (isEmpty()) { try { wait(); } catch (InterruptedException e) { e.printStackTrace(); } } Object obj = buffer[start]; start = (start + 1) % buffer.length; count--; notifyAll(); return obj; } private boolean isEmpty() { return count == 0; } private boolean isFull() { return count == buffer.length; } }
上面的代碼演示了一個生產者-消費者模型,使用wait()和notify()方法實現了線程之間的通信。
在該模型中,Buffer是一個循環隊列,當隊列已滿時,生產者線程會調用wait()方法進入等待狀態,直到有其他線程調用notify()或notifyAll()方法來喚醒它。當隊列為空時,消費者線程會調用wait()方法進入等待狀態,直到有其他線程調用notify()或notifyAll()方法來喚醒它。
原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-hk/n/186064.html