JAVA - 多線程 - 生產者與消費者

生產者消費者模型

  1. 生產者線程:能夠生產兩種產品(中文、英文),生產者產出信息後將其放到一個區域之中;
  2. 消費者線程:不停的從區域中取走生產者生產出來的產品;
  3. 產品的生產是需要耗費一定時間的。

基本實現

  • 定義一個產品類Product,作爲產品存放區;
  • 定義Productor線程,生產產品;
  • 定義Consumer線程,取走產品。
//產品
class Product {
	private String name = "蘋果";
	private String content = "愛瘋";
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getContent() {
		return content;
	}
	public void setContent(String content) {
		this.content = content;
	}	
}
//生產者線程
class Productor implements Runnable {
	private Product product = null;
	public Productor(Product product){
		this.product = product;
	}
	public void run() {
		boolean flag = true;    //控制生產哪種產品
		for(int i = 0; i < 50; i++) {
			if(flag) {     //如果flag是TRUE,生產第一種產品
				this.product.setName("蘋果");
				try {                   //線程休眠,模擬生產需要時間
					Thread.sleep(90);
				} catch (Exception e) {
					e.printStackTrace();
				}
				this.product.setContent("愛瘋");
				flag = false;
			} else {
				this.product.setName("Apple");
				try {
					Thread.sleep(90);
				} catch (Exception e) {
					e.printStackTrace();
				}
				this.product.setContent("Iphone");
				flag = true;
			}
		}		
	}	
}
//消費者線程
class Consumer implements Runnable {
	private Product product = null;
	public Consumer(Product product) {
		this.product = product;
	}
	public void run() {
		for(int i = 0; i < 50; i++) {
			try {
				Thread.sleep(100);
			} catch (Exception e) {
				e.printStackTrace();
			}
			System.out.println(this.product.getName() + " ----> " + this.product.getContent()); //取走產品
		}
	}	
}
//MAIN函數
public class ProductorConsumerDemo {
	public static void main(String[] args) {
		Product product = new Product(); //產品存放區
		Productor productor = new Productor(product);
		Consumer consumer = new Consumer(product);
		new Thread(productor).start(); //啓動生產者線程,生產產品
		new Thread(consumer).start();  //啓動消費者線程,取走產品
	}
}

 

運行結果:

Apple ----> 愛瘋
蘋果 ----> Iphone
Apple ----> 愛瘋
蘋果 ----> 愛瘋
Apple ----> Iphone
Apple ----> Iphone
Apple ----> Iphone
Apple ----> Iphone
Apple ----> Iphone
Apple ----> Iphone


存在的問題

  1. 中文產品與英文產品的信息混在一起:原因是因爲生產需要一定的時間,當生產者線程中一種產品還沒生產完就切換到消費者線程,解決方案是生產者線程在生產的時候需要加入同步操作;
  2. 生產者生產了若干個產品,消費者纔開始取走產品:原因是生產者線程在休眠的時候,消費者線程重複取走產品,解決方案是加入等待喚醒機制。

 

問題的解決

  1. 將Product類生產和讀取封裝成不同的方法,並將其設置爲同步方法;
  2. 在生產和消費方法中加入等待喚醒機制,生產方法需要等待消費方法取走產品後的通知才能繼續生產,消費方法需要等待生產方法生產完成通知後才能繼續取走。

代碼實現:

 

//產品
class Product {
	private String name = "蘋果";
	private String content = "愛瘋";
	private boolean flag = false; //是否可取走產品的標誌位,TRUE可取走,FALSE可生產
	//封裝生產方法
	public synchronized void set(String name, String content) { //同步方法解決問題一
		if(!flag) {
			try {
				super.wait();   //生產者線程等待,線程等待喚醒解決問題二
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		this.setName(name);
		try {
			Thread.sleep(300);
		} catch (Exception e) {
			e.printStackTrace();
		}
		this.setContent(content);
		flag = false;
		super.notify(); //喚醒消費者線程
	}
	
	//封裝消費方法
	public synchronized void get() {
		if(flag) {
			try {
				super.wait();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		try {
			Thread.sleep(300);
		} catch (Exception e) {
			e.printStackTrace();
		}
		System.out.println(this.getName() + " ----> " + this.getContent()); //取走產品
		flag = true;
		super.notify();
	}
	
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getContent() {
		return content;
	}
	public void setContent(String content) {
		this.content = content;
	}	
}
//生產者線程
class Productor implements Runnable {
	private Product product = null;
	public Productor(Product product){
		this.product = product;
	}
	public void run() {
		boolean flag = true;    //控制生產哪種產品
		for(int i = 0; i < 50; i++) {
			if(flag) {     //如果flag是TRUE,生產第一種產品
				this.product.set("蘋果", "愛瘋");
				flag = false;
			} else {
				this.product.set("Apple", "Iphone");
				flag = true;
			}
		}		
	}	
}
//消費者線程
class Consumer implements Runnable {
	private Product product = null;
	public Consumer(Product product) {
		this.product = product;
	}
	public void run() {
		for(int i = 0; i < 50; i++) {
			try {
				Thread.sleep(100);
			} catch (Exception e) {
				e.printStackTrace();
			}
			this.product.get();
		}
	}	
}
//MAIN函數
public class ProductorConsumerDemo {
	public static void main(String[] args) {
		Product product = new Product(); //產品存放區
		Productor productor = new Productor(product);
		Consumer consumer = new Consumer(product);
		new Thread(productor).start(); //啓動生產者線程,生產產品
		new Thread(consumer).start();  //啓動消費者線程,取走產品
	}
}


BR~

Jianwei Wang

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