正在運行的程序稱作一個進程,一個進程可以包含多個線程,這些線程可以共享進程的資源,它們共用一塊存儲空間。那么,各個線程在訪問同一個數據對象的同時,可能引起沖突,以生產者、消費者為例,就會出現隊列中沒有產品的情況下,消費者扔到隊列中去拿產品,與現實世界中邏輯不相符合。使用synchronized關鍵字可以確保線程的安全運行。
synchronized(obj){
.......
obj.wait()/notifyAll();//是數據對象而不是線程調用wait和notifyAll方法
}
當給一個線程(比如A線程)的run方法體內加入上述代碼時,說明A線程必須首先獲得該數據對象的鎖,才能對這個對象進行操作。A線程拿到這個obj數據對象的鎖以后,在它釋放以前任何其它線程都不能夠操作此對象了,之所以這樣,我們可以認為其它線程沒有這把鎖的鑰匙。A線程執行obj.wait()方法后,它將釋放其所占有的對象鎖,A線程進入阻塞狀態,同時A也就不具有了獲得obj對象所的權力,這樣其它線程就可以拿到這把鎖了。obj.notifyAll()可以喚醒因obj對象而阻塞的所有線程,並允許它們有獲得對象所的權力,obj.notify()是喚醒因obj對象而阻塞的任意一個線程。
下面的程序模仿生產者和消費者:
public class WaitAndNotify { private static List<Double> queue; public WaitAndNotify(){ queue = new ArrayList<Double>(); } public void begin(){ Thread producer = new Thread(){ public void run(){ while(true){ synchronized(queue){ double time = 1.0d; long startTime = System.currentTimeMillis(); if(System.currentTimeMillis()-startTime>=time){ startTime =System.currentTimeMillis(); for(int i=0;i<10;i++){ queue.add((Math.random()*10000)); } queue.notifyAll(); } } } } }; producer.start(); Thread consumer = new Thread(){ public void run(){ while(true){ synchronized(queue){ while(queue.isEmpty()){ System.out.println("隊列的長度為:"+queue.size()); try { queue.wait(); } catch (InterruptedException ex) { Logger.getLogger(WaitAndNotify.class.getName()).log(Level.SEVERE, null, ex); } } double result = queue.remove(0); System.out.println("成功從隊列中取到數據!"+result); } } } }; consumer.start(); } public static void main(String[] args){ WaitAndNotify obj = new WaitAndNotify(); queue.add(0.1231d); obj.begin(); } }
producer線程向queue中放入數據,並掉調用queue.notifyAll()來喚醒所有阻塞的線程,consumer線程從queue中取數據,當沒有數據時該線程就會進入阻塞狀態,等待唄喚醒。
