1. 程式人生 > >使用執行緒模擬企業的生產者和消費者

使用執行緒模擬企業的生產者和消費者

測試類:
public class Test01 {

public static void main(String[] args) {
	MyStorage storage = new MyStorage();
	
	Producer producer = new Producer(storage);
	Consumer consumer = new Consumer(storage);
	producer.setName("生產者");
	consumer.setName("銷售人員");
	
	producer.start();
	consumer.start();
}

}

/**

  • 倉庫類
  • @author Administrator

*/
import java.util.LinkedList;

public class MyStorage {
LinkedList list = new LinkedList<>(); //儲存產品
private static final int MAX_CAPACITY = 100; //倉庫的最大容量

//儲存產品 ,約定每次存10個產品 
public synchronized void store() {
	//倉庫已滿 ,生產者等待,等到消費者消費了後再繼續生產
	while ( list.size() >= MAX_CAPACITY) {
		try {
			this.wait();  	//wait()/notify()只能在同步程式碼塊中由鎖物件呼叫
			//執行wait(),執行緒等待,會釋放鎖物件,
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
	
	System.out.println( Thread.currentThread().getName() + "儲存產品 前, 倉庫容量:" + list.size());
	for( int i =1; i <= 10;i++){
		//offer屬於 offer in interface Deque<E>,add 屬於 add in interface Collection<E>。

		//當佇列為空時候,使用add方法會報錯,而offer方法會返回false。都是新增

		//作為List使用時,一般採用add / get方法來 壓入/獲取物件。

		//作為Queue使用時,才會採用 offer/poll/take等方法作為連結串列物件時,offer等方法相對來說沒有什麼意義這些方法是用於支援佇列應用的。
		list.offer(new Object());
	}
	System.out.println( Thread.currentThread().getName() + "存了10個產品後, 倉庫容量:" + list.size());
	//通知消費者消費
	this.notify();
}

//取產品 , 約定一次取10個
public synchronized void get() {
	//判斷倉庫如果已空, 消費者需要等待, 等待生產者生產了產品後再繼續消費
	while ( list.size() <= 0) {
		try {
			this.wait();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
	
	System.out.println( Thread.currentThread().getName() + "消費 前, 倉庫容量:" + list.size());
	for( int i =1; i <= 10;i++){
		//poll是減少的意思
		list.poll();
	}
	System.out.println( Thread.currentThread().getName() + "消費了10個產品 後, 倉庫容量:" + list.size());
	//通知生產者生產
	this.notifyAll();

	/*notify和notifyAll的區別

	如果執行緒呼叫了物件的 wait()方法,那麼執行緒便會處於該物件的等待池中,等待池中的執行緒不會去競爭該物件的鎖。
	當有執行緒呼叫了物件的 notifyAll()方法(喚醒所有 wait 執行緒)或 notify()方法(只隨機喚醒一個 wait 執行緒),被喚醒的的執行緒便會進入該物件的鎖池中,鎖池中的執行緒會去競爭該物件鎖。也就是說,呼叫了notify後只要一個執行緒會由等待池進入鎖池,而notifyAll會將該物件等待池內的所有執行緒移動到鎖池中,等待鎖競爭
	優先順序高的執行緒競爭到物件鎖的概率大,假若某執行緒沒有競爭到該物件鎖,它還會留在鎖池中,唯有執行緒再次呼叫 wait()方法,它才會重新回到等待池中。而競爭到物件鎖的執行緒則繼續往下執行,直到執行完了 synchronized 程式碼塊,它會釋放掉該物件鎖,這時鎖池中的執行緒會繼續競爭該物件鎖。
	*/
}

}
/**

  • 生產者執行緒
  • @author Administrator

*/
public class Producer extends Thread {
MyStorage storage;

public Producer(MyStorage storage) {
	super();
	this.storage = storage;
}

@Override
public void run() {
	//
	for(int d = 1; d <= 200; d++){
		storage.store();
	}
}

}

/**

  • 消費者執行緒
  • @author Administrator

*/
public class Consumer extends Thread {
MyStorage storage;

public Consumer(MyStorage storage) {
	super();
	this.storage = storage;
}

@Override
public void run() {
	//
	for(int d = 1; d <= 200; d++){
		storage.get();
	}
}

}