生產者消費者模式,在實際的開發過程中經常會遇到,平常我們接觸到的例如ActiveMQ就是一個一個典型的生產者消費者模式。爲了更好的理解生產者和消費這模式,下面通過自己定義的一個消息類、結合Object對象中的wait()和notify()方法實現一個簡單的生產者消費者模式。
首先定義一個消息類Info.
package com.test.consumer;
/**
* @生產消息類
*/
public class Info {
/** 消息的標題 */
private String title;
/** 消息的內容 */
private String content;
/**
* 消息的標識, 當flag=false的時候,生產者只能生產消息,消費者不能消費消息
* 當flag=true的時候,消費者只能消費消息,生產者不能生產消息
* */
private boolean flag;
/**
* 設置消息的內容
*/
public synchronized void set(String title, String content) {
if (flag == true) {
try {
super.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
this.title = title;
this.content = content;
super.notify();
this.flag = true;
}
/**
* 獲取消息內容
*/
public synchronized void get() {
if (flag == false) {
try {
super.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("標題:" + this.title + ",內容:" + this.content);
super.notify();
this.flag = false;
}
}
接着定義一個生產消息的類,默認實現Runnable接口,這樣可以在多線程的環境下進行測試。
package com.test.consumer;
/**
*生產者類
*/
public class Producer implements Runnable {
/**定義一個自己的消息類,通過構造器注入*/
private Info info;
public Producer(Info info) {
super();
this.info = info;
}
@Override
public void run() {
for (int i = 0; i < 100; i++) {
if (i % 2 == 0) {
info.set("java", "java基礎");
} else {
info.set("spring", "跟我學springMVC");
}
}
}
}
接着創建一個消費者類,同樣的實現Runnable接口
package com.test.consumer;
/**
* 消費者
*/
public class Consumer implements Runnable {
/** 定義一個自己的消息類,通過構造器注入獲取消息 */
private Info info;
public Consumer(Info info) {
super();
this.info = info;
}
@Override
public void run() {
for (int i = 0; i < 100; i++) {
this.info.get();
}
}
}
創建測試類,測試。
package com.test.consumer;
public class TestDemo {
public static void main(String[] args) {
Info info = new Info();//定義一個公共的消息類
new Thread(new Producer(info)).start();//生產者開始生產消息
new Thread(new Consumer(info)).start();//消費者開始消費消息
}
}
運行結果:
標題:java,內容:java基礎
標題:spring,內容:跟我學springMVC
標題:java,內容:java基礎
標題:spring,內容:跟我學springMVC
標題:java,內容:java基礎
標題:spring,內容:跟我學springMVC
標題:java,內容:java基礎
標題:spring,內容:跟我學springMVC
標題:java,內容:java基礎
標題:spring,內容:跟我學springMVC
標題:java,內容:java基礎
標題:spring,內容:跟我學springMVC
標題:java,內容:java基礎
標題:spring,內容:跟我學springMVC
標題:java,內容:java基礎
標題:spring,內容:跟我學springMVC
標題:java,內容:java基礎
標題:spring,內容:跟我學springMVC
標題:java,內容:java基礎
標題:spring,內容:跟我學springMVC
標題:java,內容:java基礎
標題:spring,內容:跟我學springMVC
標題:java,內容:java基礎
標題:spring,內容:跟我學springMVC
標題:java,內容:java基礎
標題:spring,內容:跟我學springMVC
標題:java,內容:java基礎
標題:spring,內容:跟我學springMVC
標題:java,內容:java基礎
標題:spring,內容:跟我學springMVC
標題:java,內容:java基礎
標題:spring,內容:跟我學springMVC
從上面的運行結果可以看出來,生產者先生產消息,然後消費者取出消息後,輸出,觀察後發現運行結果沒有錯位,即實現生產一個消息取出來一個消息。
這裏對info消息類中的set和get方法上添加了synchronized同步關鍵字,作用是在多線程的環境下能夠同步的生產存取, 屬性flag相當於一個信號燈,true和false,代表數據的兩種狀態,在flag爲true的情況下,只能生產消息,不能消費消息,消息生產完成後,將flag置爲false,表示消費者可以消費消息,同時通過notify()方法喚醒,正在等待的消費線程,開始消費消息;這個時候只能消費消息,wait()方法阻塞生產者線程,等待消費者消費完成後消費者使用notify()方法喚醒正在等待的生產者線程開始生產消息,同時flag置爲true,這個是消費者再次消費消息的時候,遇到falg=true,則進入等待阻塞狀態,這樣一次的生產、一次消費;一次生產,一次消費。