生产者——消费者模式

来源:互联网 发布:cba数据 编辑:程序博客网 时间:2024/06/05 00:54
生产者——消费者模式


1、生产者——消费者模式是一个经典的多线程设计模式,它为多线程间的协作提供了良好的解决方案。
在该模式中,通常有两个进程(生产者,消费者),生产者线程负责提交用户请求,消费者线程负责具体处理生产者提交的任务。生产者用途消费者通过共享缓存区进行通信。


2、基本结构:


生产者:提交用户请求,提取用户任务,并装入内存缓冲区
消费者:在内存缓冲区中提取并处理任务
内存缓冲区:缓存生产者提交的任务或数据,并供消费者使用
Main:使用生产者——消费者的客户端。


3、实例(生存者生产数据,消费者提取数据求整数平方)

//生产者

import java.util.Random;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;


//构建PCDate对象,并放到BlockingDeque中
public class Product implements Runnable {


private volatile boolean isRunning = true;
private BlockingQueue<PCData> queue;// 内存缓冲区
private static AtomicInteger count = new AtomicInteger();// 总数原子操作
private static final int SLEEPTTIME = 1000;


public Product(BlockingQueue<PCData> queue) {
this.queue = queue;
}


@Override
public void run() {
PCData data = null;
Random r = new Random();
System.out
.println("start product id=" + Thread.currentThread().getId());


try {
while (isRunning) {
Thread.sleep(r.nextInt(SLEEPTTIME));


data = new PCData(count.incrementAndGet());// 构造任务数据


System.out.println("product id="
+ Thread.currentThread().getId() + "========" + data
+ "is put into queue");
if (!queue.offer(data, 2, TimeUnit.SECONDS)) {// 提交数据到缓存中
System.err.println("failed to put data" + data);
}


}
} catch (InterruptedException e) {
e.printStackTrace();
Thread.currentThread().interrupt();
}
}


public void stop() {
isRunning = false;
}
}


//共享数据模型

public final class PCData {// 任务相关数据
private final int intDate;// 数据


public PCData(int d) {
intDate = d;
}


public int getIntDate() {
return intDate;
}


@Override
public String toString() {
return "PCDate [intDate=" + intDate + "]";
}


}

//消费者:
import java.text.MessageFormat;
import java.util.Random;
import java.util.concurrent.BlockingQueue;


public class Consumer implements Runnable {


private BlockingQueue<PCData> queue;// 内存缓冲区
private static final int SLEEPTTIME = 1000;


public Consumer(BlockingQueue<PCData> queue) {
this.queue = queue;
}


@Override
public void run() {
System.out.println("start consumer id="
+ Thread.currentThread().getId());
Random r = new Random(); // 随机等待时间


try {
PCData data = queue.take();// 提取任务


if (null != data) {
int re = data.getIntDate() * data.getIntDate();// 计算平方


System.out.println("consumer id="
+ Thread.currentThread().getId()+"======="
+ MessageFormat.format("{0}*{1}={2}",
data.getIntDate(), data.getIntDate(), re));


Thread.sleep(r.nextInt(SLEEPTTIME));
}


} catch (InterruptedException e) {
e.printStackTrace();
Thread.currentThread().interrupt();
}


}
}




import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ConcurrentLinkedDeque;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;


//客户端
public class Main {
public static void main(String[] args) throws InterruptedException {
// 建立缓存区


BlockingQueue<PCData> queue = new LinkedBlockingQueue<PCData>(10);


Product p1 = new Product(queue);// 建造生产者
Product p2 = new Product(queue);
Product p3 = new Product(queue);
Consumer c1 = new Consumer(queue);// 建造消费者
Consumer c2 = new Consumer(queue);
Consumer c3 = new Consumer(queue);


// 建造线程池
ExecutorService service = Executors.newCachedThreadPool();
service.execute(p1); // 运行生产者;
service.execute(p2);
service.execute(p3);
// 运行消费者
service.execute(c1);
service.execute(c2);
service.execute(c3);


Thread.sleep(10 * 1000);
p1.stop();// 停止生产者
p2.stop();
p3.stop();
Thread.sleep(3000);
service.shutdown();
}
}

生产者消费者架构图:



ConcurrentLinkedDeque是一个高性能的队列 大量使用无锁CAS操作 ,编程非常困难,有Disruptor框架
BlockingQueue只是为了方便数据共享 完全使用锁和阻塞来实现线程间的同步


结果打印:
start product id=8
start product id=9
start consumer id=11
start consumer id=13
start product id=10
start consumer id=12
product id=8========PCDate [intDate=1]is put into queue
product id=10========PCDate [intDate=2]is put into queue
consumer id=11=======1*1=1
consumer id=13=======2*2=4
product id=10========PCDate [intDate=3]is put into queue
consumer id=12=======3*3=9
product id=9========PCDate [intDate=4]is put into queue
product id=9========PCDate [intDate=5]is put into queue



每天努力一点,每天都在进步。


原创粉丝点击