生产者-消费者模式

1 基本概念

    生产者-消费者模式是一个经典的并发设计模式,它为多线程之间的协作提供了良好的解决方案。在生产者-消费者设计模式中,有两类线程:若干生产者线程和若干消费者线程。二者共享一个内存缓冲区。生产者线程向共享缓冲区中添加请求或者资源,消费者线程负责从共享缓冲区取出请求处理或者取出资源使用。

    生产者-消费者模式的核心是共享内存缓冲区,它作为生产者和消费者间的通信桥梁,避免了生产者和消费者的直接通信,实现两者之间的解耦。另外,由于缓冲区的存在,允许生产者和消费者在执行速度上存在差异,确保系统的正常运行。

2 涉及到的角色

(1)生产者:提交用户请求或者生产资源,添加到内存缓冲区。
(2)消费者:取出用户请求,然后处理,或者取出资源来使用。
(3)内存缓冲区:生产者和消费者交流信息的桥梁。缓存生产者提交的请求或者资源,供消费者使用。
(4)任务:生产者向内存缓冲区提交的数据结构。

3 代码实现

3.1不使用阻塞队列

(1)Plate.java:内存缓冲区
public class Plate {
	private List<Cake> list;
	/**
	 * 代表当前容量,即还可以再放多少块
	 */
	private int current;
	/**
	 * 总共能放多少块蛋糕
	 */
	private int capacity;
	
	public Plate(int size) {
		// TODO Auto-generated constructor stub
		list=new ArrayList<Cake>();
		current=0;
		capacity=size;
	}
	public synchronized void addCake(Cake cake) {
		
		while (current>=capacity) {
			try {
				wait();
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		System.out.println("生产蛋糕前的数量:"+current);
		list.add(cake);
		current++;
		System.out.println("生产蛋糕后的数量:"+current);
		notifyAll();
	}
	public synchronized Cake getCake() {
		while(current<=0){
			try {
				wait();
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		System.out.println("消费蛋糕前的数量:"+current);
		Cake cake=list.remove(--current);
		System.out.println("消费蛋糕后的数量:"+current);
		notifyAll();
		return cake;
	}
}
(2)Consumer.java:消费者
public class Consumer implements Runnable {
	private Plate plate;
	public Consumer(Plate plate) {
		// TODO Auto-generated constructor stub
		this.plate=plate;
	}
	@Override
	public void run() {
		// TODO Auto-generated method stub
		System.out.println("开始吃蛋糕----");
		plate.getCake();

	}
}
(3)Producer.java:生产者
public class Producer implements Runnable{
	private Plate plate;
	public Producer(Plate plate) {
		// TODO Auto-generated constructor stub
		this.plate=plate;
	}

	@Override
	public void run() {
		// TODO Auto-generated method stub
		/**
		 * 这里限制了一个生产者只能生产一次蛋糕,而且只能生产一个,可以进行优化
		 * 
		 */
		System.out.println("开始生产蛋糕");
		plate.addCake(new Cake("cake"+Thread.currentThread().getId()));
	}
}
(4)Cake.java:
public class Cake {
	private String brand;
	public Cake(String brand) {
		// TODO Auto-generated constructor stub
		this.brand=brand;
	}
	public String getBrand() {
		return brand;
	}
}
(5)Main.java:
public class Main {
	public static void main(String[] args) {
		Plate plate=new Plate(5);
		for(int i=0;i<5;i++){
			new Thread(new Producer(plate)).start();
		}
		for (int i = 0; i < 3; i++) {
			new Thread(new Consumer(plate)).start();
		}
	}

}

3.2 使用阻塞队列

(1)Producer.java:
/**
 * 使用阻塞队列
 * @author 深蓝色
 *
 */
public class Producer implements Runnable {
	private BlockingQueue<Cake> queue;
	public Producer(BlockingQueue<Cake> queue) {
		// TODO Auto-generated constructor stub
		this.queue=queue;
	}
	
	@Override
	public void run() {
		// TODO Auto-generated method stub
		/**
		 * 这里设置为一个生产者生产完一次蛋糕后,还可以继续生产
		 */
		while (true) {
			Cake cake=new Cake("cake"+Thread.currentThread().getId());
			try {
				System.out.println("生产一块蛋糕");
				/**
				 * 注意不要调用offer方法,因为当空间不足时,offer方法不会阻塞而是直接添加失败
				 */
				queue.put(cake);
				/**
				 * 模拟耗时操作或者休息
				 */
				Thread.sleep(100);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		
	}
}
(2)Consumer.java:
public class Consumer implements Runnable{
	private BlockingQueue<Cake> queue;
	public Consumer(BlockingQueue<Cake> queue) {
		// TODO Auto-generated constructor stub
		this.queue=queue;
	}
	@Override
	public void run() {
		// TODO Auto-generated method stub
		/**
		 * 一个消费者可以吃多次蛋糕
		 */
		while (true) {
			System.out.println("吃一块蛋糕----");
			try {
				queue.take();
				Thread.sleep(100);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}
}
(3)Main.java:
public class Main {
	public static void main(String[] args) {
		/**
		 * 这个盘子的容量设置为3
		 */
		BlockingQueue<Cake> queue=new LinkedBlockingDeque<Cake>(3);
		for (int i = 0; i < 2; i++) {
			new Thread(new Producer(queue)).start();
		}
		
		for (int i = 0; i < 5; i++) {
			new Thread(new Consumer(queue)).start();
		}
		
	}
}

4 参考文献

1>.Java程序性能优化.葛一鸣 等著.
2>.Java并发编程实践.
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值