Java多線程:生產者-消費者模型

生產者生產,消費者消費,理想的情況下是生產者每生產一個產品,消費者就消費一個產品,生產者還沒有生產的時候消費者等待,消費者還沒有消費完產品的時候生產者等待。

class Producer implements Runnable{    // 生產者
	private Message msg;
	
	public Producer(Message msg) {
		this.msg = msg;
	}
	
	@Override
	public void run() {
		for(int i = 0; i < 100; i++) {
			try {
				Thread.sleep(100);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			if(i % 2 == 0) {
				this.msg.setTitle("產品-1");
				this.msg.setContent("oppo手機");
			}
			else {
				this.msg.setTitle("產品-2");
				this.msg.setContent("vivo手機");
			}
		}
	}
}

class Consumer implements Runnable{    // 消費者
	private Message msg;
	
	public Consumer(Message msg) {
		this.msg = msg;
	}
	@Override
	public void run() {
		for(int i = 0; i < 100; i++) {
			try {
				Thread.sleep(100);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			System.out.println("消費則消費:" + this.msg.getTitle() + " -  " + this.msg.getContent());;
		}
	}
	
}

class Message{    // 生產者和消費者通過Message建立聯繫
	private String title;
	private String content;
	
	public void setContent(String content) {
		this.content = content;
	}
	public void setTitle(String title) {
		this.title = title;
	}
	

	public String getTitle() {
		return title;
	}
	public String getContent() {
		return content;
	}
	
}
public class Main{
	
	public static void main(String args[]) throws Exception {
		
		Message msg = new Message();
		new Thread(new Producer(msg)).start();	// 啓動生產者線程
		new Thread(new Consumer(msg)).start();	// 啓動消費者線程
	}
}

運行結果顯示出現了數據不同步的問題,那麼接下來就解決數據不同步的問題

修改代碼:

class Message{
	private String title;
	private String content;
	
	// 進行同步處理
	public synchronized void set(String title, String content) {
		this.title = title;
		this.content = content;
	}
	
	public synchronized String get() {
		return this.title + " -  " + this.content;
	
	}
}

把同步處理放到Message類後可以解決數據不同步問題,但是不能解決數據重複問題。

如果想要解決生產者與消費者的問題,最好的解決方案是使用等待與喚醒機制。

對於等待和喚醒的操作機制主要依靠的是Object類提供的方法處理的:

 

  • 等待:2,3可以設置等待時間
  1. public final void wait​() throws InterruptedException

Causes the current thread to wait until another thread invokes the notify() method or the notifyAll() method for this object. In other words, this method behaves exactly as if it simply performs the call wait(0).

  1. public final void wait​(long timeout) throws InterruptedException

Causes the current thread to wait until either another thread invokes the notify() method or the notifyAll() method for this object, or a specified amount of time has elapsed. The current thread must own this object's monitor.

  1. public final void wait​(long timeout, int nanos) throws InterruptedException

Causes the current thread to wait until another thread invokes the notify() method or the notifyAll() method for this object, or some other thread interrupts the current thread, or a certain amount of real time has elapsed.

  • 喚醒:
  1. 喚醒第一個等待線程:public final void notify​()
  2. 喚醒所有等待線程:public final void notifyAll​()

notify()喚醒第一個等待的線程,notifyAll()喚醒所有等待的線程,這樣優先級高的有可能會先執行

 

再次修改Message類:

class Message{
	private String title;
	private String content;
	private boolean flag = true;	// 表示生產或消費的標誌
	// flag == true 表示允許生產,但不允許消費
	// flag == false 表示允許消費,但不允許生產
	
	// 進行同步處理
	public synchronized void set(String title, String content) {
		if(this.flag == false) {	// 如果不能生產則應該等待
			try {
				super.wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		this.title = title;
		this.content = content;
		this.flag = false;	// 已經生產過了
		super.notify();		// 通知正在等待的消費者可以消費了
	}
	
	public synchronized String get() {
		if(this.flag == true) {		// 如果不能消費則應該等待
			try {
				super.wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		
		try {	// 先算出return後的表達式的值,然後執行finally,最後return
			return this.title + " -  " + this.content;
		}finally {
			flag = true;	// 消費過了
			super.notify();	// 通知正在等待的生產者可以生產了
		}
		
	}
}

運行結果:

完整代碼:

class Producer implements Runnable{
	private Message msg;
	
	public Producer(Message msg) {
		this.msg = msg;
	}
	
	@Override
	public void run() {
		for(int i = 0; i < 100; i++) {
			try {
				Thread.sleep(100);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			if(i % 2 == 0) {
				System.out.println("生產產品1");
				this.msg.set("產品-1", "oppo手機");
			}
			else {
				System.out.println("生產產品2");
				this.msg.set("產品-2", "vivo手機");
			}
		}
	}
}

class Consumer implements Runnable{
	private Message msg;
	
	public Consumer(Message msg) {
		this.msg = msg;
	}
	@Override
	public void run() {
		for(int i = 0; i < 100; i++) {
			try {
				Thread.sleep(100);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			System.out.println("消費則消費:" + this.msg.get());
		}
	}
	
}

class Message{
	private String title;
	private String content;
	private boolean flag = true;	// 表示生產或消費的標誌
	// flag == true 表示允許生產,但不允許消費
	// flag == false 表示允許消費,但不允許生產
	
	// 進行同步處理
	public synchronized void set(String title, String content) {
		if(this.flag == false) {	// 如果不能生產則應該等待
			try {
				super.wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		this.title = title;
		this.content = content;
		this.flag = false;	// 已經生產過了
		super.notify();		// 通知正在等待的消費者可以消費了
	}
	
	public synchronized String get() {
		if(this.flag == true) {		// 如果不能消費則應該等待
			try {
				super.wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		
		try {	// 先算出return後的表達式的值,然後執行finally,最後return
			return this.title + " -  " + this.content;
		}finally {
			flag = true;	// 消費過了
			super.notify();	// 通知正在等待的生產者可以生產了
		}
		
	}
}
public class Main{
	
	public static void main(String args[]) throws Exception {
		
		Message msg = new Message();
		new Thread(new Producer(msg)).start();	// 啓動生產者線程
		new Thread(new Consumer(msg)).start();	// 啓動消費者線程
	}
}

 

 

 

 

 

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