生产者消费者模式,在实际的开发过程中经常会遇到,平常我们接触到的例如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,则进入等待阻塞状态,这样一次的生产、一次消费;一次生产,一次消费。