并发编程:生产者-消费者模式

        除了Futrue模式和Master-Worker模式,生产者-消费者模式也是一个非常经典的多线程模式。在生产者-消费者模式中,通常有两类线程(即N+1个生产者和N+1个消费者的线程),生产者负责提交用户请求,消费者则负责进行具体的业务处理,生产者和消费者之间通过共享内存缓存区(MQ)进行通信。下面以一段小例子进行模拟:

        Data:数据类,模拟生产者和消费者所操作的数据,设置两个属性:String id和String name,代码如下:

public class Data {
	private String id;
	private String name;
	public Data(String id,String name) {
		this.id = id;
		this.name = name;
	}
	...
         get/set方法
        ...
	@Override
	public String toString() {
		return "Data [id=" + id + ", name=" + name + "]";
	}
}

        Provider:生产者,负责实例化新的data数据,包括一条BlockingQueue<Data>的队列引用:messageQueue(生产者将其实例化的数据存放到该队列里边);用于停止生产的开关:isRunning(一个boolean类型,使用volatile修饰的变量);ID生成器:count(new AtomicInteger(),在生产数据时使用);一个随机数:r(new Random(System.currentTimeMillis()),用于模拟生产者获取数据的时间)。具体代码如下:

public class Provider implements Runnable {
	// 设置内存缓存区
	BlockingQueue<Data> messageQueue;
	//多线程开关
	private volatile boolean isRunning = true;
	//id生成器
	private static AtomicInteger count = new AtomicInteger();
	//随机对象
	private static Random r = new Random(System.currentTimeMillis()); 
	
	@SuppressWarnings("unused")
	private Provider() {}
	public Provider(BlockingQueue<Data> messageQueue) {
		this.messageQueue = messageQueue;
	}
	
	@Override
	public void run() {
		while(isRunning) {
			try {
				//随机睡眠,表示获取数据所产生的时间
				Thread.sleep(r.nextInt(5)*1000);
				//累计获取的数据
				int id = count.incrementAndGet();
				//获取Data
				Data data  = new Data(Integer.toString(id),"数据:"+id);
				System.err.println("当前线程(生产者)"+Thread.currentThread().getName()+",获取了数据,id为:"+id+",将其加载到公共缓存");
				if(!this.messageQueue.offer(data,2,TimeUnit.SECONDS)){
					System.err.println("提交缓冲区数据失败...");
				}
			}catch(Exception e) {
				System.err.println(e.getMessage());
			}
		}
	}
	public void stop() {
		this.isRunning = false;
	}
}

        Customer:消费者,用于对生产者实例化放入队列的数据的处理。包括一条BlockingQueue<Data>队列的引用:messageQueue。具体代码如下:

package _12_生产者消费者模式;

import java.util.Random;
import java.util.concurrent.BlockingQueue;

public class Customer implements Runnable{
	// 设置内存缓存区
	BlockingQueue<Data> messageQueue;
	@SuppressWarnings("unused")
	private Customer() {}
	public Customer(BlockingQueue<Data> messageQueue) {
		this.messageQueue = messageQueue;
	}
	//随机对象
	private static Random r = new Random();
	
	@Override
	public void run() {
		while(true) {
			try {
				//获取数据
				Data data = this.messageQueue.take();
				//进行数据处理
				Thread.sleep(r.nextInt(3)*1000);
				System.err.println("当前线程(消费者):"+Thread.currentThread().getName()+"消费成功,消费数据Id为:"+data.getId());
			}catch(Exception e) {
				System.err.println(e.getMessage());
			}
		}
		
	}

}

        MainTest:测试类,用于实例化X个生产者和Y个消费者并使生产者生产2秒钟的数据,然后停止生产数据,消费者则对阻塞队列里边的数据进行处理。具体代码如下:

package _12_生产者消费者模式;

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

public class MainTest {

	public static void main(String[] args) {
		// 设置内存缓存区
		BlockingQueue<Data> messageQueue = new LinkedBlockingQueue<Data>(10);
		//生产者
		Provider provider_01 = new Provider(messageQueue);     		 
		Provider provider_02 = new Provider(messageQueue);     		 
		Provider provider_03 = new Provider(messageQueue);    		 	 
		Provider provider_04 = new Provider(messageQueue);     	
		Provider provider_05 = new Provider(messageQueue);    
		Provider provider_06 = new Provider(messageQueue);   
		Provider provider_07 = new Provider(messageQueue);   
		Provider provider_08 = new Provider(messageQueue);    
		//消费者
		Customer customer_01 = new Customer(messageQueue); 		 
		Customer customer_02 = new Customer(messageQueue); 		 
		//创建一个线程池,一个缓存的线程池,可创建无穷的线程,没有任务时不创建线程,空闲线程存活时间为默认(60秒)
		ExecutorService cachePool = Executors.newCachedThreadPool();
		cachePool.execute(provider_05);
		cachePool.execute(provider_06);
		cachePool.execute(provider_07);
		cachePool.execute(provider_08);
		cachePool.execute(provider_04);
		cachePool.execute(customer_01);
		cachePool.execute(provider_03);
		cachePool.execute(customer_02);
		cachePool.execute(provider_02);
		cachePool.execute(provider_01);
		try {
			Thread.sleep(5*1000);
		}catch(Exception e) {
			System.err.println(e.getMessage());
		}
		provider_04.stop();
		provider_03.stop();
		provider_02.stop();
		provider_01.stop();
		provider_05.stop();
		provider_06.stop();
		provider_07.stop();
		provider_08.stop();
		try {
			Thread.sleep(2*1000);
		}catch(Exception e) {
			System.err.println(e.getMessage());
		}
/*		cachePool.shutdown();
		cachePool.shutdownNow();*/
		
	}

}

运行效果如下:

当前线程(生产者)pool-1-thread-5,获取了数据,id为:4,将其加载到公共缓存
当前线程(生产者)pool-1-thread-3,获取了数据,id为:2,将其加载到公共缓存
当前线程(消费者):pool-1-thread-6消费成功,消费数据Id为:3
...                            //消费者和生产者运行中
当前线程(生产者)pool-1-thread-1,获取了数据,id为:26,将其加载到公共缓存
提交缓冲区数据失败...           //由于生产者产生数据比消费者处理速度快,此时队列已满,数据不能放入
当前线程(消费者):pool-1-thread-8消费成功,消费数据Id为:15
                              //队列里边的数据被处理,产生空闲,生产者继续产生数据并放入阻塞队列
当前线程(生产者)pool-1-thread-2,获取了数据,id为:28,将其加载到公共缓存
当前线程(生产者)pool-1-thread-4,获取了数据,id为:30,将其加载到公共缓存
当前线程(消费者):pool-1-thread-8消费成功,消费数据Id为:18
...
//直至阻塞队列里边的数据处理完成

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值