版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/AnselLyy/article/details/80960616
欢迎访问 我的个人博客
- 也叫缓存绑定问题(bounded- buffer),是一个经典的、多进程同步问题
- 分为 1. 单生产者和单消费者 和 2. 多生产者和多消费者 两种
单生产者和单消费者
有两个进程:一组生产者进程和一组消费者进程共享一个初始为空、固定大小为n的缓存(缓冲区)。
生产者的工作是制造一段数据,只有缓冲区没满时,生产者才能把消息放入到缓冲区,否则必须等待,如此反复;
同时,只有缓冲区不空时,消费者才能从中取出消息,一次消费一段数据(即将其从缓存中移出),否则必须等待。由于缓冲区是临界资源,它只允许一个生产者放入消息,或者一个消费者从中取出消息。
关键点
- 要保证不让生产者在缓存还是满的时候仍然要向内写数据
- 不让消费者试图从空的缓存中取出数据
描述
在生产者-消费者模式中,通常有两类线程,即若干个生产者线程和若干个消费者线程。
生产者线程负责提交用户请求,消费者线程负责处理用户请求。生产者和消费者之间通过共享内存缓冲区进行通信。生产者-消费者模式中的内存缓冲区的主要功能是数据在多线程间的共享。
此外,通过该缓冲区,可以缓解生产者和消费者之间的性能差。
案例
通过馒头和篮子的案例进行示范
馒头(实体类)
class ManTou {
int id;
public ManTou(int id) {
// TODO Auto-generated constructor stub
this.id = id;
}
@Override
public String toString() {
// TODO Auto-generated method stub
return "馒头: " + id;
}
}
篮子(实体类 | 共享的数据池)
class SyncBasket {
int index = 0;
ManTou[] basket = new ManTou[6];
// 放馒头
public synchronized void push(ManTou manTou) {
while (index == basket.length) {
try {
// 如果篮子已经满了,那就将该线程放入等锁池中,等待篮子中的馒头被消费
this.wait();
} catch (InterruptedException e) {
// TODO: handle exception
e.printStackTrace();
}
}
this.notifyAll();
basket[index++] = manTou;
System.out.println("生产了: " + manTou);
}
// 取馒头
public synchronized ManTou pop() {
while (index == 0) {
try {
// 如果篮子为空的,那就将该线程放入等锁池中,直到有新的馒头放入篮子中
this.wait();
} catch (InterruptedException e) {
// TODO: handle exception
e.printStackTrace();
}
}
this.notifyAll();
System.out.println("消费了: " + basket[--index]);
return basket[index];
}
}
生产者(Producer)
class Producer implements Runnable {
private SyncBasket sync;
public Producer(SyncBasket syncBasket) {
// TODO Auto-generated constructor stub
this.sync = syncBasket;
}
@Override
public void run() {
// TODO Auto-generated method stub
for (int i = 0; i < 20; i++) {
ManTou manTou = new ManTou(i);
sync.push(manTou);
// try {
// // 沉睡一秒
// Thread.sleep(1000);
//
// } catch (InterruptedException e) {
// // TODO: handle exception
// e.printStackTrace();
// }
}
}
}
消费者(Consumer)
class Consumer implements Runnable {
private SyncBasket sync;
public Consumer(SyncBasket syncBasket) {
// TODO Auto-generated constructor stub
this.sync = syncBasket;
}
@Override
public void run() {
// TODO Auto-generated method stub
for (int i = 0; i < 20; i++) {
sync.pop();
}
}
}
Test
public class ProducerAndConsumer {
public static void main(String[] args) {
SyncBasket syncBasket = new SyncBasket();
Producer producer = new Producer(syncBasket);
Thread t1 = new Thread(producer);
Consumer consumer = new Consumer(syncBasket);
Thread t2 = new Thread(consumer);
t1.start();
t2.start();
}
}