1. 程式人生 > >執行緒間通訊,生產者消費者問題!

執行緒間通訊,生產者消費者問題!

2、忙等待

1.執行緒間通訊的共享物件(Product)

Product類是生產者與消費者的共享類,是實現他們之間資料的共享物件。生產者生產Product,消費者消費Product,所以在Product類中,分別有一個make和一個sale方法。注意,在這兩個方法中,都使用了synchronized關鍵字,實現執行緒安全機制。在每個方法中,還用到了wait和notify方法, Obj.wait(),與Obj.notify()必須要與synchronized(Obj)一起使用,也就是wait,與notify是針對已經獲取了Obj鎖進行操作,從語法角度來說就是Obj.wait(),Obj.notify必須在synchronized(Obj){...}語句塊內。從功能上來說wait就是說執行緒在獲取物件鎖後,主動釋放物件鎖,同時本執行緒休眠。直到有其它執行緒呼叫物件的notify()喚醒該執行緒,才能繼續獲取物件鎖,並繼續執行。相應的notify()就是對物件鎖的喚醒操作。但有一點需要注意的是notify()呼叫後,並不是馬上就釋放物件鎖的,而是在相應的synchronized(){}語句塊執行結束,自動釋放鎖後,JVM會在wait()物件鎖的執行緒中隨機選取一執行緒,賦予其物件鎖,喚醒執行緒,繼續執行。
具體程式碼如下:

<span style="font-size:18px;">import java.util.ArrayList;
import java.util.List;

public class Product {
	private String name;
	private int count;
	public static List<Product> list = new ArrayList<Product>();

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getCount() {
		return list.size();
	}

	public void setCount(int count) {
		this.count = count;
	}

	public static List<Product> getList() {
		return list;
	}

	public static void setList(List<Product> list) {
		Product.list = list;
	}

	// /生產方法
	public synchronized void make(Product p) {
		if (getCount() > 9) {
			try {
				this.wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		} else {
			this.notifyAll();
			list.add(p);
		}
	}

	// /消費
	public synchronized void sale() {
		if (getCount() < 1) {
			try {
				this.wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		} else {
			this.notifyAll();
			list.remove(0);
		}

	}
}
</span>

2.生產者類,生產者類實現了Runnable介面,所以是一個執行緒類。原始碼如下:
<span style="font-size:18px;">public class Maker implements Runnable {
	Product product = new Product();
	public Maker(Product product) {
		this.product = product;
	}
	public void run() {
		while (true) {
			try {
				Thread.sleep(500);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			Product p = new Product();
			p.setName("aaa");
			product.make(p);
			System.out.println("生產:當前剩餘產品-->" + product.getCount());
		}

	}

}
</span>

3.消費者類,消費者類也實現了Runnable介面。
<span style="font-size:18px;">public class Saler implements Runnable {
	
	Product product = new Product();
	public Saler(Product product) {
		this.product = product;
	}
	public void run() {
		while (true) {
			try {
				Thread.sleep(300);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			product.sale();
			System.out.println("消費:當前剩餘產品-->" + product.getCount());
		}
	}
}
</span>
4.測試程式碼如下,在測試程式碼中,分別建立了四個生產者執行緒和兩個消費者執行緒。
<span style="font-size:18px;">public class Test {
	public static void main(String[] args) {
		Product product = new Product();
		Maker maker = new Maker(product);
		Saler saler = new Saler(product);
		Thread m1 = new Thread(maker);
		Thread m2 = new Thread(maker);
		Thread m3 = new Thread(maker);
		Thread m4 = new Thread(maker);
		Thread s1 = new Thread(saler);
		Thread s2 = new Thread(saler);
		m1.start();
		m2.start();
		m3.start();
		m4.start();
		s1.start();
		s2.start();
	}
}
</span>

5.執行結果如果下,執行結果中我們可以看到,生產者生產商品的數量,不會超過10個,當商品數量超過10個的時候,生產者就會停止生產,而是等待消費者消費了一定量的商品,才會繼續生產。同樣,當剩餘商品的數量小於0時,消費者也不會繼續消費。這就實現了生產者與消費者間的執行緒通訊,兩者共享一個數據物件。