本实例中单独为生产者和消费者各开辟一个线程作为生产者和消费者的执行线程,在生产者消费者设计模式中存在一个数据缓冲区,使生产者和消费者的“生产”和“消费”动作都在该缓冲区进行,这样做的目的就是保证了生产者和消费者的完美解耦,试想一下如果没了这个缓冲区,生产者和消费者中的方法互调,那么两个类的关联度(耦合度)就会很高,一旦一个发生变化,势必会影响另外一个;
下面开始我们的实例:
首先是生产者的代码:
/**
* 生产者
*/
public class Product implements Runnable{
private Queue queue;
public Product(Queue queue){
this.queue = queue;
}
@Override
public void run() {
try{
for(int i = 0; i < 10; i++){
queue.product("Product------" + "No." + i);//开始生产
}
}catch (Exception e){
e.printStackTrace();
}
}
}
这是消费者:
/**
* 消费者
*/
public class Consumer implements Runnable{
private Queue queue;
public Consumer(Queue queue){
this.queue = queue;
}
@Override
public void run() {
try{
for(int i = 0; i < 10; i++){
System.out.println("already gone : " + queue.consumer());//开始消费
}
}catch (Exception e){
e.printStackTrace();
}
}
}
这是缓冲区,几乎所有的逻辑都是在这里实现的:
/**
* 队列缓冲区
*/
public class Queue {
private Object signal = new Object();//当前线程的挂起和执行标记
private boolean isFull = false;//队列是否已满
private List list = new ArrayList<>();//队列
public void product(String msg) throws Exception{
synchronized (signal){
if(!isFull){//如果没有满,执行如下代码
list.add(msg);//加进队列
isFull = true;
System.out.println("Product One !");
signal.notify();//唤醒当前消费者里面被挂起的线程
}
signal.wait();//否则,如果当前满了,说明消费者正在消费,挂起当前生产线程
}
}
public String consumer() throws Exception{
synchronized (signal){
if(!isFull){
//不满,说明生产者正在生产,应当挂起consumer线程
System.out.println("Empty Product !");
signal.wait();
}
isFull = false;//已消费,队列被标记为不满状态
signal.notify();//通知生产者
}
//消费(读取)
String result = "";
if(list.size() > 0){
result = this.list.get(list.size() - 1);
this.list.remove(list.size() - 1);
}
return result;
}
}
上面这个模式利用java现有的阻塞队列很容易实现,可以避免上述代码中很大一部分代码(线程的挂起、唤醒、队列弹出数据等)