1. 程式人生 > >基於執行緒通訊實現多生產者多消費者模式

基於執行緒通訊實現多生產者多消費者模式

前言:

執行緒開始執行,擁有自己的棧空間,但是如果每個執行中的執行緒,如果僅僅是孤立地執行,那麼沒有一點兒價值,或者是價值很小,如果多執行緒能夠相互配合完成工作的話,這將帶來巨大的價值,這也就是執行緒間的通訊啦。在java中多執行緒間的通訊使用的是等待/通知機制來實現的。
具體而言: 是指一個執行緒A1呼叫了物件B的wait()方法進入等待狀態,而另一個執行緒A2呼叫了物件B的notify()或者notifyAll()方法,執行緒A1收到通知後從物件B的wait()方法返回,進而執行後續操作。上述的兩個執行緒通過物件B來完成互動,而物件上的wait()和notify()/notifyAll()的關係就如同開關訊號一樣,用來完成等待方和通知方之間的互動工作。

程式碼設計:

本文以生產蘋果和消費蘋果為例子
AppleResource.java

package CP;


/**
 *@author superxing
 * @time 2018年11月21日 
 * @decrition 蘋果資源
 */
public class AppleResource {
	
	private String name;
	private int count = 1;//蘋果的初始數量
	private boolean flag = false;//判斷是否有需要執行緒等待的標誌
	/**
	 * 生產蘋果
	 */
	public synchronized void product(String name){
		while(flag){
			//此時有蘋果,等待
			try {
				this.wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		this.name=name+count;//設定蘋果的名稱
		count++;
		System.out.println(Thread.currentThread().getName()+"...生產者..."+this.name);
		flag=true;//有蘋果後改變標誌
		notifyAll();//通知消費執行緒可以消費了
	}
	
	/**
	 * @author superxing
     * @time 2018年11月21日 
	 * 消費蘋果
	 */
	public synchronized void consume(){
		while(!flag){//如果沒有蘋果就等待
			try{this.wait();}catch(InterruptedException e){}
		}
		System.out.println(Thread.currentThread().getName()+"...消費者........"+this.name);//消費蘋果1
		flag = false;
		notifyAll();//通知生產者生產蘋果
	}
}

MutilProducerConsumer.java

package CP;


/**
 * @author superxing
 * @time 2018年11月21日 
 * @decrition 多生產者多消費者模式
 */
public class MutilProducerConsumer {
	
	public static void main(String[] args) 
	{
		AppleResource r = new AppleResource();
		Mutil_Producer pro = new Mutil_Producer(r);
		Mutil_Consumer con = new Mutil_Consumer(r);
		//生產者執行緒
		Thread t0 = new Thread(pro);
		Thread t1 = new Thread(pro);
		//消費者執行緒
		Thread t2 = new Thread(con);
		Thread t3 = new Thread(con);
		//啟動執行緒
		t0.start();
		t1.start();
		t2.start();
		t3.start();
	}
}
/**
 * @author superxing
 * @time 2018年11月21日 
 * @decrition 生產者執行緒
 */
class Mutil_Producer implements Runnable
{
	private AppleResource r;
	Mutil_Producer(AppleResource r)
	{
		this.r = r;
	}
	public void run()
	{
		while(true)
		{
			r.product("蘋果");
		}
	}
}
/**
 * @author superxing
 * @time 2018年11月21日 
 * @decrition 消費者執行緒
 */
class Mutil_Consumer implements Runnable
{
	private AppleResource r;
	Mutil_Consumer(AppleResource r)
	{
		this.r = r;
	}
	public void run()
	{
		while(true)
		{
			r.consume();
		}
	}
}


程式碼思考:

通過網上尋找資料和思考,用兩組條件物件(Condition也稱為監視器)來實現等待/通知機制,也就是說通過已有的鎖獲取兩組監視器,一組監視生產者,一組監視消費者。notifyAll()和signalAll()方法去喚醒池中的執行緒,然後讓池中的執行緒又進入 競爭佇列去搶佔CPU資源,這樣不僅喚醒了無關的執行緒而且又讓全部執行緒進入了競爭佇列中,而我們最後使用兩種監聽器分別監聽生產者執行緒和消費者執行緒,這樣的方式恰好解決前面兩種方式的問題所在,我們每次喚醒都只是生產者執行緒或者是消費者執行緒而不會讓兩者同時喚醒,這樣不就能更高效得去執行程式了嗎?