生产者消费者问题的Java实现

生产者消费者问题是研究多线程程序时绕不开的经典问题之一,它描述是有一块缓冲区作为仓库,生产者可以将产品放入仓库,消费者则可以从仓库中取走产品。解决生产者/消费者问题的方法可分为两类:(1)采用某种机制保护生产者和消费者之间的同步;(2)在生产者和消费者之间建立一个管道。第一种方式有较高的效率,并且易于实现,代码的可控制性较好,属于常用的模式。第二种管道缓冲区不易控制,被传输数据对象不易于封装等,实用性不强。因此本文只介绍同步机制实现的生产者/消费者问题。

同步方法有三种:wait()/notify()、await()/signal()和BlockingQueue队列

本文只讲解await()/signal()和BlockingQueue队列

1、await()/signal()方法

import java.util.LinkedList;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

public class Storage {//缓冲区类
	private LinkedList<Object> list=new LinkedList<>();
	private int maxSize=10;
	private ReentrantLock lock=new ReentrantLock();
	private Condition notEmpty=lock.newCondition();
	private Condition notFull=lock.newCondition();
	
	public void setMaxSize(int maxSize){
		this.maxSize=maxSize;
	}
	
	public void produce(){
		try {
			lock.lockInterruptibly();
			while(list.size()==maxSize){
				System.out.println("仓库已满,暂时无法执行生产任务");
				notFull.await();
			}
			list.add(new Object());
			System.out.println(Thread.currentThread().getName()
					+"生产了一个产品,现在仓库储量为:"+list.size());
			notEmpty.signalAll();
			
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		finally{
			lock.unlock();
		}
	}
	
	public void consume(){
		try {
			lock.lockInterruptibly();
			while(list.size()==0){
				System.out.println("仓库已空,暂时无法执行消费任务");
				notEmpty.await();
			}
			list.remove();
			System.out.println(Thread.currentThread().getName()
					+"消费了一个产品,现在仓库储量为:"+list.size());
			notFull.signalAll();
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		finally{
			lock.unlock();
		}
	}

}
import java.util.Random;

public class Producer implements Runnable{
	private Storage storage;
	private boolean isRunning=true;
	public Producer(Storage storage){
		this.storage=storage;
	}
	
	public void run(){
		try {
			while(isRunning){
				Thread.sleep(new Random().nextInt(1000));
				storage.produce();
			}
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	public void stop(){
		isRunning=false;
	}

}
import java.util.Random;

public class Consumer implements Runnable{
	private Storage storage;
	private boolean isRunning=true;
	public Consumer(Storage storage){
		this.storage=storage;
	}

	@Override
	public void run() {
		try{
			while(isRunning){
				Thread.sleep(new Random().nextInt(1000));
				storage.consume();
			}
		}
		catch(InterruptedException e){
			e.printStackTrace();
		}
		
	}
	
	public void stop(){
		isRunning=false;
	}

}
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Test {

	public static void main(String[] args) {
		Storage storage=new Storage();
		Producer producer1=new Producer(storage);
		Producer producer2=new Producer(storage);
		Producer producer3=new Producer(storage);
		Consumer consumer1=new Consumer(storage);
		Consumer consumer2=new Consumer(storage);
		Consumer consumer3=new Consumer(storage);
		ExecutorService exe=Executors.newCachedThreadPool();
		exe.execute(producer1);
		exe.execute(producer2);
		exe.execute(producer3);
		exe.execute(consumer1);
		exe.execute(consumer2);
		exe.execute(consumer3);
		
		exe.shutdown();
	}
}

部分运行结果:

pool-1-thread-6消费了一个产品,现在仓库储量为:3
pool-1-thread-5消费了一个产品,现在仓库储量为:2
pool-1-thread-4消费了一个产品,现在仓库储量为:1
pool-1-thread-6消费了一个产品,现在仓库储量为:0
仓库已空,暂时无法执行消费任务
pool-1-thread-3生产了一个产品,现在仓库储量为:1
pool-1-thread-4消费了一个产品,现在仓库储量为:0
pool-1-thread-3生产了一个产品,现在仓库储量为:1
pool-1-thread-1生产了一个产品,现在仓库储量为:2
pool-1-thread-2生产了一个产品,现在仓库储量为:3
pool-1-thread-5消费了一个产品,现在仓库储量为:2
pool-1-thread-5消费了一个产品,现在仓库储量为:1
pool-1-thread-4消费了一个产品,现在仓库储量为:0
pool-1-thread-3生产了一个产品,现在仓库储量为:1
pool-1-thread-4消费了一个产品,现在仓库储量为:0
仓库已空,暂时无法执行消费任务
仓库已空,暂时无法执行消费任务
pool-1-thread-1生产了一个产品,现在仓库储量为:1
pool-1-thread-4消费了一个产品,现在仓库储量为:0
仓库已空,暂时无法执行消费任务
仓库已空,暂时无法执行消费任务
仓库已空,暂时无法执行消费任务
pool-1-thread-1生产了一个产品,现在仓库储量为:1

2、BlockingQueue队列

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

public class Producer_Queue implements Runnable{
	private BlockingQueue<Object> queue;
	private boolean isRunning=true;
	public Producer_Queue(BlockingQueue<Object> queue){
		this.queue=queue;
	}
	
	public synchronized void run(){
		while(isRunning){
			try {
				Thread.sleep(new Random().nextInt(1000));
				queue.put(new Object());
				System.out.println(Thread.currentThread().getName()+
						"生产了一个产品,现仓库储量为:"+queue.size());
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
		}
	}
	
	public void stop(){
		isRunning=false;
	}

}
import java.util.Random;
import java.util.concurrent.*;

public class Consumer_Queue implements Runnable{
	private BlockingQueue<Object> queue;
	private boolean isRunning=true;
	public Consumer_Queue(BlockingQueue<Object> queue){
		this.queue=queue;
	}
	
	public void run(){
		while(isRunning){
			try {
				Thread.sleep(new Random().nextInt(1000));
				queue.take();
				System.out.println(Thread.currentThread().getName()+
						"消费了一个产品,现仓库储量为:"+queue.size());
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
		}
	}
	
	public void stop(){
		isRunning=false;
	}

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

public class BlcokingQueue_PS {

	public static void main(String[] args) throws InterruptedException {
		BlockingQueue<Object> queue=new LinkedBlockingQueue<>(5);
		Consumer_Queue c1=new Consumer_Queue(queue);
		Consumer_Queue c2=new Consumer_Queue(queue);
		Consumer_Queue c3=new Consumer_Queue(queue);
		Producer_Queue p1=new Producer_Queue(queue);
		Producer_Queue p2=new Producer_Queue(queue);
		Producer_Queue p3=new Producer_Queue(queue);
		ExecutorService exe=Executors.newCachedThreadPool();
		exe.execute(c1);
		exe.execute(c2);
		exe.execute(c3);
		exe.execute(p1);
		exe.execute(p2);
		exe.execute(p3);
		
		Thread.sleep(2000);
		p1.stop();
		p2.stop();
		p3.stop();
		c1.stop();
		c2.stop();
		c3.stop();
		exe.shutdown();
	}
}

运行结果:

pool-1-thread-4生产了一个产品,现仓库储量为:0
pool-1-thread-2消费了一个产品,现仓库储量为:0
pool-1-thread-5生产了一个产品,现仓库储量为:1
pool-1-thread-2消费了一个产品,现仓库储量为:0
pool-1-thread-6生产了一个产品,现仓库储量为:1
pool-1-thread-1消费了一个产品,现仓库储量为:0
pool-1-thread-4生产了一个产品,现仓库储量为:1
pool-1-thread-3消费了一个产品,现仓库储量为:0
pool-1-thread-4生产了一个产品,现仓库储量为:1
pool-1-thread-2消费了一个产品,现仓库储量为:0
pool-1-thread-5生产了一个产品,现仓库储量为:1
pool-1-thread-3消费了一个产品,现仓库储量为:0
pool-1-thread-6生产了一个产品,现仓库储量为:1
pool-1-thread-2消费了一个产品,现仓库储量为:0
pool-1-thread-4生产了一个产品,现仓库储量为:1
pool-1-thread-1消费了一个产品,现仓库储量为:0
pool-1-thread-4生产了一个产品,现仓库储量为:1
pool-1-thread-5生产了一个产品,现仓库储量为:2
pool-1-thread-6生产了一个产品,现仓库储量为:3
pool-1-thread-4生产了一个产品,现仓库储量为:4
pool-1-thread-3消费了一个产品,现仓库储量为:3
pool-1-thread-2消费了一个产品,现仓库储量为:2
pool-1-thread-1消费了一个产品,现仓库储量为:1
有时使用BlockingQueue可能会出现put()和System.out.println()输出不匹配的情况,这是由于它们之间没有同步造成的。由于生产者在调用put()生产产品之后,还没来得及执行println(),消费者就调用take()方法消费掉了产品。
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值