一、
生产者和消费者模式是通过一个容器来解决生产者和消费者的强耦合问题。生产者和消
费者彼此之间不直接通信,而是通过阻塞队列来进行通信,所以生产者生产完数据之后不用等待消费者处理,直接扔给阻塞队列,消费者不找生产者要数据,而是直接从阻塞队列里取,阻塞队列就相当于一个缓冲区,平衡了生产者和消费者的处理能力。这个阻塞队列就是用来给生产者和消费者解耦的。纵观大多数设计模式,都会找一个第三者出来进行解耦,如工厂模式的第三者是工厂类,模板模式的第三者是模板类。在学习一些
设计模式的过程中,先找到这个模式的第三者,能帮助我们快速熟悉一个设计模式。
用三种方式实现生产者消费者模式
任务Model类
public class TaskData {
private int taskid;
private int amout;
private int jobnum;
public TaskData(int taskid, int amout, int jobnum) {
this.taskid = taskid;
this.amout = amout;
this.jobnum = jobnum;
}
public int getTaskid() {
return taskid;
}
public void setTaskid(int taskid) {
this.taskid = taskid;
}
public int getAmout() {
return amout;
}
public void setAmout(int amout) {
this.amout = amout;
}
public int getJobnum() {
return jobnum;
}
public void setJobnum(int jobnum) {
this.jobnum = jobnum;
}
}
二、synchronized+wait/notify 方式
Produce:
package produceAndConsume;
import java.util.Queue;
public class Produce implements Runnable{
private final int CAPACITY=10;
private Queue<TaskData> queue;
private TaskData taskData;
public Produce(Queue queue,TaskData taskData){
this.queue = queue;
this.taskData=taskData;
}
@Override
public void run() {
while (true)
synchronized (queue){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
while (queue.size()==CAPACITY){
System.out.println(Thread.currentThread().getName()+":任务队列已满...执行wait方法...");
try {
queue.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
queue.offer(taskData);
System.out.println(Thread.currentThread().getName()+":添加一个任务"+taskData.getTaskid()+"唤醒其他线程...");
queue.notifyAll();
}
}
}
Consume:
package produceAndConsume;
import java.util.Queue;
public class Consume implements Runnable {
private Queue<TaskData> queue;
public Consume(Queue queue){
this.queue = queue;
}
@Override
public void run() {
while (true)
synchronized (queue){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
while (queue.size()==0){
System.out.println(Thread.currentThread().getName()+":任务队列已空...执行wait方法...");
try {
queue.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName()+":删除一个任务"+queue.poll().getTaskid()+"唤醒其他线程...");
queue.notifyAll();
}
}
}
测试:
package produceAndConsume;
import java.util.LinkedList;
import java.util.Queue;
public class DataModel {
public static void main(String[] args) {
TaskData taskData = new TaskData(1001,10,002530);
TaskData taskData1 = new TaskData(1002,40,002530);
TaskData taskData2 = new TaskData(1003,30,002530);
TaskData taskData3 = new TaskData(1004,50,002530);
Queue<TaskData> queue = new LinkedList<TaskData>();
Produce produce = new Produce(queue,taskData);
Produce produce1 = new Produce(queue,taskData1);
Produce produce2 = new Produce(queue,taskData2);
Produce produce3 = new Produce(queue,taskData3);
Consume consume = new Consume(queue);
Consume consume1 = new Consume(queue);
new Thread(produce).start();
new Thread(produce1).start();
new Thread(produce2).start();
new Thread(produce3).start();
new Thread(consume).start();
new Thread(consume1).start();
}
}
三、lock + condition方式
produce:
package produceAndConsume;
import java.util.Queue;
import java.util.Random;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
public class ProduceByCon implements Runnable{
private Queue<TaskData> queue;
int max_value;
private TaskData taskData;
private Lock lock;
private Condition fullcondition;
private Condition emptycondition;
public ProduceByCon(Queue<TaskData> queue, int max_value, TaskData taskData, Lock lock, Condition fullcondition,Condition emptycondition) {
this.queue = queue;
this.max_value = max_value;
this.taskData = taskData;
this.lock = lock;
this.fullcondition=fullcondition;
this.emptycondition=emptycondition;
}
@Override
public void run() {
while(true){
lock.lock();
while (queue.size()==max_value){//while替换成if就有虚假唤醒问题
try {
System.out.println(Thread.currentThread().getName()+"线程已满,进入睡眠...");
fullcondition.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
queue.offer(taskData);
try {
Thread.sleep(new Random().nextInt(100));
} catch (Exception e) {
System.out.println(Thread.currentThread().getName()+"当前线程:");
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"队列插入:"+taskData.getTaskid()+"queue.size="+queue.size());
fullcondition.signal();
emptycondition.signal();
lock.unlock();
}
}
}
consume:
package produceAndConsume;
import java.util.Queue;
import java.util.Random;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
public class ConsumeByCon implements Runnable {
private Condition fullcondition;
private Condition emptycondition;
private Queue<TaskData> queue;
private Lock lock;
public ConsumeByCon(Condition fullcondition, Condition emptycondition, Queue<TaskData> queue, Lock lock) {
this.fullcondition = fullcondition;
this.emptycondition = emptycondition;
this.queue = queue;
this.lock = lock;
}
@Override
public void run() {
while (true){
lock.lock();
while (queue.size()==0){//while替换成if就有虚假唤醒问题
try {
System.out.println(Thread.currentThread().getName()+"线程已空,进入await...");
emptycondition.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
try {
Thread.sleep(new Random().nextInt(100));
} catch (Exception e) {
// System.out.println(Thread.currentThread().getName());
e.printStackTrace();
}
System.out.print(Thread.currentThread().getName()+"队列删除之前:"+ queue.size()+",");
System.out.println(queue.poll().getTaskid()+"queue.size="+queue.size());
emptycondition.signal();
fullcondition.signal();
lock.unlock();
}
}
}
测试
package produceAndConsume;
import java.util.Queue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class Test2 {
public static void main(String[] args) {
final Lock lock = new ReentrantLock();
final Condition full = lock.newCondition();
Condition empty = lock.newCondition();
Queue queue = new LinkedBlockingQueue();
TaskData taskData = new TaskData(1001,10,002530);
TaskData taskData1 = new TaskData(1002,40,002530);
TaskData taskData2 = new TaskData(1003,30,002530);
TaskData taskData3 = new TaskData(1004,50,002530);
ProduceByCon produceByCon = new ProduceByCon(queue,10,taskData,lock,full,empty);
ProduceByCon produceByCon1 = new ProduceByCon(queue,10,taskData1,lock,full,empty);
ProduceByCon produceByCon2 = new ProduceByCon(queue,10,taskData2,lock,full,empty);
ProduceByCon produceByCon3 = new ProduceByCon(queue,10,taskData3,lock,full,empty);
ConsumeByCon consumeByCon = new ConsumeByCon(full,empty,queue,lock);
ConsumeByCon consumeByCon1 = new ConsumeByCon(full,empty,queue,lock);
ConsumeByCon consumeByCon2 = new ConsumeByCon(full,empty,queue,lock);
new Thread(produceByCon).start();
new Thread(produceByCon1).start();
new Thread(produceByCon2).start();
new Thread(produceByCon3).start();
new Thread(consumeByCon).start();
new Thread(consumeByCon1).start();
new Thread(consumeByCon2).start();
}
}
四、阻塞队列方式
produce
package produceAndConsume;
import java.util.Random;
import java.util.concurrent.LinkedBlockingDeque;
public class ProduceByBq implements Runnable{
private LinkedBlockingDeque<TaskData> linkedBlockingDeque;
private TaskData taskData;
public ProduceByBq(LinkedBlockingDeque<TaskData> linkedBlockingDeque, TaskData taskData) {
this.linkedBlockingDeque = linkedBlockingDeque;
this.taskData = taskData;
}
@Override
public void run() {
while (true){
try {
Thread.sleep(new Random().nextInt(1000));
linkedBlockingDeque.put(taskData);
System.out.println(Thread.currentThread().getName()+"插入:"+taskData.getTaskid()+"当前que.size="+linkedBlockingDeque.size());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
comsume:
package produceAndConsume;
import java.util.Random;
import java.util.concurrent.LinkedBlockingDeque;
public class ConsumeByBQ implements Runnable{
private LinkedBlockingDeque<TaskData> linkedBlockingDeque;
public ConsumeByBQ(LinkedBlockingDeque<TaskData> linkedBlockingDeque) {
this.linkedBlockingDeque = linkedBlockingDeque;
}
@Override
public void run() {
while (true){
try {
Thread.sleep(new Random().nextInt(1000));
System.out.println(Thread.currentThread().getName()+"消费"+linkedBlockingDeque.take().getTaskid()+"当前que.size="+linkedBlockingDeque.size());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
测试:
package produceAndConsume;
import java.util.concurrent.LinkedBlockingDeque;
public class Test {
public static void main(String[] args) {
LinkedBlockingDeque<TaskData> linkedBlockingDeque = new LinkedBlockingDeque<TaskData>(10);
TaskData taskData = new TaskData(1001,10,002530);
TaskData taskData1 = new TaskData(1002,40,002530);
TaskData taskData2 = new TaskData(1003,30,002530);
ConsumeByBQ consumeByBQ = new ConsumeByBQ(linkedBlockingDeque);
ConsumeByBQ consumeByBQ1 = new ConsumeByBQ(linkedBlockingDeque);
ProduceByBq produceByBq = new ProduceByBq(linkedBlockingDeque,taskData);
ProduceByBq produceByBq1 = new ProduceByBq(linkedBlockingDeque,taskData1);
ProduceByBq produceByBq2 = new ProduceByBq(linkedBlockingDeque,taskData2);
new Thread(consumeByBQ).start();
new Thread(consumeByBQ1).start();
new Thread(produceByBq).start();
new Thread(produceByBq1).start();
new Thread(produceByBq2).start();
}
}