學習筆記7:wait(),notify()與notifyAll()及消費者生產者小案例

1.wait(),notify()與notifyAll():java

    wait(),notify()與notifyAll方法是java.lang.Object類的方法,因此這些方法不能被子類重寫,Object類是全部類的超類。
ide

void wait() 致使線程進入等待狀態,直到它被其餘線程經過notify()或者notifyAll喚醒
void wait(long t) //毫秒
在其餘線程調用此對象的 notify() 方法或notifyAll()方法,或者超過指定的時間量前,致使當前線程等待。
void wait(long t, int n)

a.  其餘線程經過調用 notify 方法,或 notifyAll 方法通知在此對象的監視器上等待的線程醒來。函數

b.  timeout 毫秒值與 nanos 毫微秒參數值之和指定的超時時間已用完。 測試

// wait(0) 與wait(0,0)相同this

void notify()
隨機選擇一個在該對象上調用wait方法的線程,解除其阻塞狀態。 (單個線程)
void notifyAll()

喚醒在此對象監視器上等待的全部線程。spa



wait(),notify(),notifyAll()必須寫在同步方法中(synchronized方法內部或者synchronized塊內部),這是由於這幾個方法要求當前正在運行Object.wait()方法的線程擁有Object的對象鎖,即當前線程必須擁有此對象監視器,不然將會拋出IllegalMonitorStateException(若是當前線程不是此對象監視器的全部者)。即便你確實知道當前上下文線程確實擁有了對象鎖,也不能將Object.wait()這樣的語句寫在當前上下文中。線程


wait():釋放佔有的對象鎖,線程進入等待池,釋放cpu,而其餘正在等待的線程便可搶佔此鎖,得到鎖的線程便可運行程序。而sleep()不一樣的是,線程調用此方法後,會休眠一段時間,休眠期間,會暫時釋放cpu,但並不釋放對象鎖。也就是說,在休眠期間,其餘線程依然沒法進入此代碼內部。休眠結束,線程從新得到cpu,執行代碼。wait()和sleep()最大的不一樣在於wait()會釋放對象鎖,而sleep()不會code

notify(): 該方法會喚醒由於調用對象的wait()而等待的線程,其實就是對對象鎖的喚醒,從而使得wait()的線程能夠有機會獲取對象鎖。調用notify()後,並不會當即釋放鎖,而是繼續執行當前代碼,直到synchronized中的代碼所有執行完畢,纔會釋放對象鎖。JVM則會在等待的線程中調度一個線程去得到對象鎖,執行代碼。須要注意的是,wait()和notify()必須在synchronized代碼塊中調用。notifyAll()則是喚醒全部等待的線程。orm


2.簡單的生產者消費者例子:對象

//首先設定一個存放產品的緩衝區:

public class CollectionBuffer {
	//緩衝區最大存儲量
	private final int MAX_SIZE = 100;
	//緩衝區存儲量載體
	LinkedList<Object> list = new LinkedList<Object>();  // 此實現並不是同步 

	public LinkedList<Object> getList() {
		return list;
	}
	public void setList(LinkedList<Object> list) {
		this.list = list;
	}
	public int getMAX_SIZE() {
		return MAX_SIZE;
	}
	
	//生產產品 num 個
	public void produce( int num ){
		//同步代碼塊
		synchronized(list){
			//若是倉庫剩餘量不足,即生產產品可能過多  
			while( list.size() + num > MAX_SIZE ){
				System.out.println("即將生產產品數量爲: " + num +"  但已有庫存量爲: "+ list.size() +"  暫時不能再進行生產任務<產品數量會大於最大庫存量>");
				try {
					//等會再生產,陷入等待狀態(阻塞) 會釋放對象鎖,而sleep不會
					list.wait();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
			//若是知足條件,則生產產品:
			for( int i=1;i<=num;i++){
				list.add( new Object() );
			}
			
			System.out.println("已經生產產品數量爲:" + num  + "  現生產後新的庫存量爲:" + list.size() );
			
			list.notifyAll();
		}
	}
	

	//消費產品 num 個
	public void consume( int num ){
		// 同步代碼塊
		synchronized(list){
			while( list.size() < num ){
				System.out.println("想要消費產品數量爲: " + num +"  但當前庫存產品量爲: " + list.size() +"   暫時還不能消費<庫存量小於消費量>");
				try {
					// 不知足消費條件,等待(阻塞)
					list.wait();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
			
			//若是知足消費條件, 即庫存量足夠消費者消費 消費量小於庫存量。
			for( int i=1;i<=num;i++){
				list.remove();
			}
			System.out.println("已經消費產品數量爲: " + num  + "  現消費後新的庫存量爲: " + list.size() );
			
			list.notifyAll();
		}
	}
	
}


// 生產者:

public class Producer extends Thread {
	// 每次生產的產品量
	private int num;
	
	//存放的倉庫(緩衝容器)
	private CollectionBuffer collectionBuffer;

	// 構造函數 設置存儲緩衝區倉庫
	public Producer(CollectionBuffer collectionBuffer){
		this.collectionBuffer = collectionBuffer;
	}
	
	@Override
	public void run() {
		 // 調用倉庫緩衝區CollectionBuffer的生產函數  
		collectionBuffer.produce(num);
	}

	public int getNum() {
		return num;
	}

	public void setNum(int num) {
		this.num = num;
	}

	public CollectionBuffer getCollectionBuffer() {
		return collectionBuffer;
	}

	public void setCollectionBuffer(CollectionBuffer collectionBuffer) {
		this.collectionBuffer = collectionBuffer;
	}
	
}


//消費者:
public class Consumer extends Thread{
	//每次要消費的產品量:
	private int num;
	
	//消費產品的緩衝倉庫區
	private CollectionBuffer collectionBuffer;
	
	//構造函數 指定消費商品的緩衝區
	public Consumer(CollectionBuffer collectionBuffer){
		this.collectionBuffer = collectionBuffer;
	}
	
	@Override
	public void run() {
		//調用緩衝區中的消費產品的函數,指定消費量
		collectionBuffer.consume(num);
	}

	public int getNum() {
		return num;
	}

	public void setNum(int num) {
		this.num = num;
	}

	public CollectionBuffer getCollectionBuffer() {
		return collectionBuffer;
	}

	public void setCollectionBuffer(CollectionBuffer collectionBuffer) {
		this.collectionBuffer = collectionBuffer;
	}

}

// 測試類:
public class TestPC {
	public static void main(String[] args) throws InterruptedException {
		
		//建立倉庫緩衝區對象
		CollectionBuffer cb = new CollectionBuffer();
		
		//建立多個生產者對象
		Producer p1 = new Producer(cb);
		Producer p2 = new Producer(cb);
		Producer p3 = new Producer(cb);
		Producer p4 = new Producer(cb);
		Producer p5 = new Producer(cb);
		Producer p6 = new Producer(cb);
		//建立多個消費者對象
		Consumer c1 = new Consumer(cb);
		Consumer c2 = new Consumer(cb);
		Consumer c3 = new Consumer(cb);
		Consumer c4 = new Consumer(cb);
		Consumer c5 = new Consumer(cb);
		Consumer c6 = new Consumer(cb);
		
		//開始設置生產者生產產品數量
		p1.setNum(10);
		p2.setNum(20);
		p3.setNum(30);
		p4.setNum(60);
		p5.setNum(80);
		p6.setNum(90);
		
		//開始讓消費者消費產品數量
		c1.setNum( 80 );
		c2.setNum( 60 );
		c3.setNum( 50 );
		c4.setNum( 35 );
		c5.setNum( 20 );
		c6.setNum( 10 );
		
		
		// 讓線程開始執行
		c1.start();
		c2.start();
		p1.start();
		p2.start();
		c6.start();
		p4.start();
		c3.start();
		p3.start();
		p5.start();
		c4.start();
		p6.start();
		c5.start();
		
	}

}
相關文章
相關標籤/搜索