java 多線程學習筆記------(4)線程協作(併發控制)

java 多線程學習筆記------(4)線程協作(併發控制)

線程協作:

生產者消費者模式

應用場景:生產者和消費者問題
  • 假設倉庫中只能存放一件產品,生產者將生產出來的產品放入 倉庫,消費者將倉庫中產品取走消費;
  • 如果倉庫中沒有產品,則生產者將產品放入倉庫,否則停止生 產並等待,直到倉庫中的產品被消費者取走爲止;
  • 如果倉庫中放有產品,則消費者可以將產品取走消費,否則停 止消費並等待,直到倉庫中再次放入產品爲止。

分析:這是一個線程同步問題,生產者和消費者共享同一個資源,並且生產者和消 費者之間相互依賴,互爲條件
  • 對於生產者,沒有生產產品之前,要通知消費者等待。而生產了產品之後, 又需要馬上通知消費者消費
  • 對於消費者,在消費之後,要通知生產者已經消費結束,需要繼續生產新 產品以供消費
  • 在生產者消費者問題中,僅有synchronized是不夠的
    • synchronized可阻止併發更新同一個共享資源,實現了同步
    • synchronized不能用來實現不同線程之間的消息傳遞(通信)
解決方式1:併發協作模型“生產者/消費者模式”   管程法
  • 生產者:負責生產數據的模塊(這裏模塊可能是:方法、對象、線程、進程);
  • 消費者:負責處理數據的模塊(這裏模塊可能是:方法、對象、線程、進程);
  • 緩衝區:消費者不能直接使用生產者的數據,它們之間有個“緩衝區”; 生產者將生產好的數據放入“緩衝區”,消費者從“緩衝區”拿要處理的數據。

解決方式2:併發協作模型“生產者/消費者模式”  信號燈法

Java提供了3個方法解決線程之間的通信問題
在這裏插入圖片描述均是java.lang.Object類的方法 都只能在同步方法或者同步代碼塊中使用,否則會拋出異常

管程法:

package Thread;


/**
 * 協作模型:生產者消費者實現方式一:
 * 管程法:藉助緩衝區
 * @author 賭徒
 *
 */
public class Cooperation {
	public static void main(String[] args) {
		Syncontiner continer=new Syncontiner();
		new Productor(continer).start();
		new Consumer(continer).start();
	}
	

}
//生產者
class Productor extends Thread{
	Syncontiner continer;
	public Productor(Syncontiner continer) {
		this.continer = continer;
	}
	public void run() {
		for (int i = 0; i < 100; i++) {
			System.out.println("生產--->第"+i+"個");
			continer.push(new Datas(i));
		}
	}
}
//消費者
class Consumer extends Thread{
	Syncontiner continer;
	public Consumer(Syncontiner continer) {
		this.continer = continer;
	}
	public void run() {
for (int i = 0; i < 100; i++) {
	System.out.println("消費--->第"+continer.pop().ID+"個");
	
		}
	}
}
//緩衝區
class Syncontiner{
	Datas[]datas=new Datas[10];//存儲數據容器
	int count=0;//計數器
	
	//儲存 生產
	public synchronized void push(Datas data) {
		//何時生產 容器有空間
		//不能生產 等待
		if (count==datas.length) {
			try {
				this.wait();//線程阻塞  消費者通知生產,阻塞取消
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		datas[count]=data;
        count++;
        this.notifyAll();//存在數據 喚醒
	}
	//獲取  消費
	public synchronized Datas pop() {
		//何時消費 容器中是否有數據
		//沒有數據等待
		if (count==0) {
			try {
				this.wait();//線程阻塞 生產者通知消費,阻塞取消
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		count--;
		Datas data=datas[count];
		this.notifyAll();//存在空間 喚醒
		return data;
	}
	
}
//數據
class Datas{
	int ID;

	public Datas(int iD) {
		
		ID = iD;
	}
}

信號燈法:

package Thread;

/**
 *  協作模型:生產者消費者實現方式二:
 *信號燈法
 * @author 賭徒
 *
 */
public class Cooperation1 {

	public static void main(String[] args) {

		TV tv=new TV();
		new Player(tv).start();
		new Watcher(tv).start();
	}

}

//生產者 演員
class Player extends Thread{
	TV tv;
	public Player(TV tv) {
		this.tv = tv;
	}
	public void run() {
		for (int i = 0; i <20; i++) {
			if (i%2==0) {
				this.tv.play("你好");
			}else {
				this.tv.play("嗨");
			}
		}
	}
}

//消費者 觀衆
class Watcher extends Thread{
	TV tv;
	public Watcher(TV tv) {
		this.tv = tv;
	}
	public void run() {
		for (int i = 0; i < 20; i++) {
			tv.watch();
		}
	}
}
//同一個資源 電視

class TV{
	String voice;
	//信號燈
	//T 表示演員表演 觀衆等待
	//F 表示觀衆觀看 演員等待
	boolean flag=true;
	
	//表演
	public synchronized void play(String voice) {
		//演員等待
		if (!flag) {
			try {
				this.wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		System.out.println("表演了:"+voice);
		this.voice=voice;
		this.notifyAll();
		this.flag=!this.flag;
	}
	
	//觀看
	public synchronized void watch() {
		//觀衆等待
		if (flag) {
			try {
				this.wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}

		System.err.println("聽到了:"+voice);
		this.notifyAll();
		this.flag=!this.flag;
	}
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章