Java生产者消费者模型

生产者-消费者模型是一个多线程并发协作得模型。主要思想是:通过一个阻塞队列让生产者和消费者之间间接通信,生产者生产完数据后不用等待消费者处理,而是交给阻塞队列,消费者也不用跟生产者直接要数据,而是从阻塞队列里取。这个阻塞队列解决了生产者和消费者之间强耦合的问题,平衡了生产者和消费者的处理能力。

模拟生产者和消费者:Main类(5个消费者和1个生产者)

public static void main(String[] args) {
		//阻塞队列
		MyBlockingQueue2 taskQueue = new MyBlockingQueue2();
		
		//生成任务编号
		AtomicInteger taskNumber = new AtomicInteger(1);
		
		//创建固定数量的线程池(一个生产者,五个消费者)
		ExecutorService executorService = Executors.newFixedThreadPool(6);
		
		//5个消费者
		for(int i=0;i<5;i++) {
			executorService.execute(new Runnable() {
				@Override
				public void run() {
						while(true) {
							try {
								//消费者不断的从阻塞队列中获取(消费)任务
								String item = taskQueue.take();
								System.out.println("[消费者]"+Thread.currentThread().getName()+"获取任务"+item);
							} catch (InterruptedException e) {
								System.out.println("[消费者]"+Thread.currentThread().getName()+"中断结束!");
							}
							
						}
				}
			});
		}
		
		//生产者
		executorService.execute(new Runnable() {
			@Override
			public void run() {
				//10个任务
				for(int i=0;i<10;i++) {
					String s = "task"+taskNumber.getAndIncrement();
					System.out.println("[生产者]生成任务:"+s);
					//将生成的任务放入阻塞队列
					taskQueue.put(s);
					try {
						Thread.sleep(100);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
				//10个任务提交结束
				executorService.shutdownNow();
			}
		});
		
	}
自定义阻塞队列:MyBlockingQueue类(使用notifyAll+wait的方式)

put()方法用于模拟生产者将数据任务放入阻塞队列中,并调用notifyll()方法唤醒所有的线程任务。

take()方法用于模拟消费者从阻塞队列中获取队头数据任务,在获取锁时,先判断阻塞队列是否为空,如果为空,让线程进入等待并释放锁,被put(()方法的this.notifyAll();唤醒时,会重新获取锁。

public class MyBlockingQueue {
	//使用LinkedList 作为队列的存储容器
	private Queue<String> queue = new LinkedList<String>();
	
	//添加元素(生产的数据任务)放入队尾
	public synchronized void put(String task) {
		//将数据任务放入阻塞队列中
		queue.offer(task);
		//唤醒所有线程(通知所有线程有线程任务进入阻塞队列)
		this.notifyAll();
	}
	
	//获取队列的对头元素(消费者获取数据任务)
	public synchronized String take() throws InterruptedException{
		//判断阻塞队列会否为空
		while(queue.isEmpty()) {
			//获取this锁(如果队列为空)
			this.wait();//进入等待,释放this锁
			//被put()的notifyAll唤醒时
			//this.notifyAll()  让当前线程重新获取锁
		}
        //返回队头元素
		return queue.poll();
		
	}
}
自定义阻塞队列:MyBlockingQueue2类(使用signalAll+await的方式)

使用ReentrantLock进行线程同步,使用ReentranLock可以通过Condition的signalAll()和await()。

signalAll():唤醒所有等待的线程

signal():随机唤醒等待线程中得一个

await():无限等待

await(等待毫秒值):等待某一时间后自动被唤醒

public class MyBlockingQueue2 {
	//使用LinkedList 作为队列的存储容器
	private Queue<String> queue = new LinkedList<String>();
	//ReentrantLock锁
	private final ReentrantLock lock = new ReentrantLock();
	//Condition接口:定义了signalAll()和await()作用等同于notifyAll()和wait()
	private final Condition condition = lock.newCondition();
	
	//添加元素(生产的数据任务)放入队尾
	public void put(String task) {
		//定义临时变量,引用当前锁
		final ReentrantLock lock = this.lock;
		//加锁
		lock.lock();
		try {
			queue.offer(task);
			//唤醒所有线程(通知所有线程有线程任务进入阻塞队列)
			condition.signalAll();//作用等同于 notify()
		}finally{
			//释放锁
			lock.unlock();
		}
	}
	
	//获取队列的对头元素(消费者获取数据任务)
	public synchronized String take() throws InterruptedException{
		final ReentrantLock lock = this.lock;
		lock.lock();
		try {
			while(queue.isEmpty()) {
				//获取this锁(队列为空)
				condition.await();//作用等同于 wait() ,无限等待,通过signalAll()唤醒
				//condition.await(1,TimeUnit.SECONDS);//进入等待,1秒钟超时后唤醒,作用等同于wait()
			}
			//返回队头元素
			return queue.poll();
		}finally {
			lock.unlock();
		}
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值