生产者消费者设计模式学习
一、什么是生产者消费者设计模式
Java中的生产者-消费者设计模式是一种用于多线程编程的经典设计模式,它用于解决多个线程之间共享资源时的同步和通信问题。这个模式主要用在有数据生产者(Producer)和数据消费者(Consumer)的场景中,生产者负责产生数据,而消费者负责消费数据。
二、为什么会有这种模式
在线程世界里,生产者就是生产数据的线程,消费者就是消费数据的线程。
在多线程开发当中,如果生产者处理速度很快,而消费者处理速度很慢,那么生产者就必须等待消费者处理完,才能继续生产数据。同样的道理,如果消费者的处理能力大于生产者,那么消费者就必须等待生产者。
为了解决这种生产消费能力不均衡的问题,所以便有了生产者和消费者模式。
三、是用来解决什么问题的
- 资源共享:在多线程环境中安全地共享资源。
- 数据同步:确保生产者不会在没有消费者的情况下过度填充缓冲区,反之亦然。
- 异步通信:允许生产者和消费者独立工作,但又能在适当的时候交互。
四、如何解决的
上个小demo
package com.ljh.producerconsumer;
import java.util.LinkedList;
import java.util.Queue;
public class producerConsumerDemo {
public static void main(String[] args) {
Buffer buffer=new Buffer();
Consumer consumer=new Consumer(buffer);
Producer producer=new Producer(buffer);
producer.start();
consumer.start();
}
}
/**
* 生产者类,继承自Thread,负责向缓冲区添加数据。
* 该类的实例将作为一个线程运行,不断地向缓冲区添加数据。
*/
class Producer extends Thread {
/**
* 缓冲区对象,用于存储生产者产生的数据。
*/
private Buffer buffer;
/**
* 构造函数,初始化生产者的缓冲区。
*
* @param buffer 缓冲区实例,生产者将向这个缓冲区添加数据。
*/
public Producer(Buffer buffer) {
this.buffer = buffer;
}
/**
* 重写run方法,定义生产者的线程执行逻辑。
* 生产者会循环10次,每次向缓冲区添加一个数字,并休眠1秒。
*/
@Override
public void run() {
for (int i = 0; i < 10; i++) {
try {
// 向缓冲区添加数据。
buffer.add(i);
// 休眠1秒,模拟生产数据的过程。
Thread.sleep(1000);
} catch (InterruptedException e) {
// 如果线程被中断,抛出运行时异常。
throw new RuntimeException(e);
}
}
}
}
/**
* 消费者类,继承自Thread,负责从缓冲区获取数据并消费。
*/
class Consumer extends Thread {
/**
* 缓冲区对象,用于存储和提取数据。
*/
private Buffer buffer;
/**
* 构造函数,初始化消费者类的缓冲区对象。
*
* @param buffer 缓冲区对象,用于数据消费。
*/
public Consumer(Buffer buffer) {
this.buffer = buffer;
}
/**
* 重写run方法,定义消费者线程的执行逻辑。
* 主要负责从缓冲区获取数据并打印,重复执行10次。
*/
@Override
public void run() {
for (int i = 0; i < 10; i++) {
int val = 0;
try {
// 从缓冲区获取数据,如果被中断则抛出RuntimeException。
val = buffer.pull();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
// 打印消费了的数据。
System.out.println("消费了" + val);
}
}
}
/**
* Buffer类用于实现一个固定大小的缓冲区。
* 它使用队列来存储数据,并且支持线程安全的添加和提取数据操作。
*/
class Buffer {
/**
* 使用LinkedList作为队列实现,因为其在添加和删除操作上具有较好的性能。
*/
private Queue<Integer> queue = new LinkedList<>();
/**
* 缓冲区的大小被固定为5,这个大小决定了可以存储的最大数据量。
*/
private int size = 5;
/**
* 向缓冲区中添加一个数据项。
* 如果缓冲区已满,则当前线程进入等待状态,直到缓冲区有空位。
*
* @param val 要添加到缓冲区的值。
* @throws InterruptedException 如果线程在等待时被中断。
*/
public synchronized void add(int val) throws InterruptedException {
// 如果队列已满,则等待直到有空间可用。
if (queue.size() > size) {
wait();
}
// 添加新值到队列。
queue.add(val);
// 唤醒其他等待的线程,可能有线程在等待消费数据。
notify();
}
/**
* 从缓冲区中提取一个数据项。
* 如果缓冲区为空,则当前线程进入等待状态,直到有数据可用。
*
* @return 从缓冲区中提取的数据项。
* @throws InterruptedException 如果线程在等待时被中断。
*/
public synchronized int pull() throws InterruptedException {
// 如果队列为空,则等待直到有数据可用。
if (queue.size() == 0) {
wait();
}
// 提取并返回队列的第一个元素。
int val = queue.poll();
// 唤醒其他等待的线程,可能有线程在等待添加数据。
notify();
return val;
}
}
标签:消费者,生产者,buffer,线程,缓冲区,设计模式,数据
From: https://www.cnblogs.com/jhhhred/p/18316903