生产者和消费者场景中的问题
分享一下工作和学习中的一些知识点。
平时在许多业务场景中,总会碰到一些生产者和消费者的问题,比如生产者和消费者操作的都是同一类产品,也可以说是同一个资源,既然是同一个资源,那么就会存在线程不安全问题(也可能出现在同步方法中)。我分享一个方法,管程法。
生产者
字面意思就是制造产品的一个对象,比如餐馆的厨师就是生产者,将菜品炒出来供客户享用。
消费者
就是消耗产品的一方,就比如刚举得例子里面的客户就是消费方,消费生产者生产的产品。
生产者和消费者的关系
生产者将生产出来的产品放入缓冲区,然后消费者从缓冲区去拿产品出来消费。这里用到缓冲区的原因,是因为这里演示的场景是生产者和消费者同时运行,生产者不知道我需要生产到什么时候停止,消费者也不知道我到底要消费多少,所以需要一个缓冲区来让双方知道,生产者知道我生产的产品还有多少剩余,消费者知道还有没有产品让我消费。像B2B这种业务的,我提前告诉你我能生产多少,或者消费者告诉你我要多少的,那就不存在这个问题了。(有问题还请大家评论里告诉我)
代码测试
class Test{
public static void main(String[] args) {
SyncBuffer syncBuffer=new SyncBuffer();
new Productor(syncBuffer).start();
new Consumer(syncBuffer).start();
}
}
//生产者,消费者,缓冲区,产品
//生产者
class Productor extends Thread{
SyncBuffer syncBuffer;
public Productor(SyncBuffer syncBuffer){
this.syncBuffer=syncBuffer;
}
@Override
public void run() {
//生产
for (int i = 0; i < 100; i++) {
syncBuffer.push(new Product(i));
System.err.println("生产者生产了"+i+"商品");
}
}
}
//消费者
class Consumer extends Thread {
SyncBuffer syncBuffer;
public Consumer(SyncBuffer syncBuffer){
this.syncBuffer=syncBuffer;
}
@Override
public void run() {
//消费
for (int i = 0; i < 100; i++) {
System.err.println("消费者消费了"+syncBuffer.pop().getId()+"商品");
}
}
}
//产品
class Product{
private int id;
public Product(int id) {
this.id = id;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
}
//缓冲区
class SyncBuffer{
Product [] products =new Product[10];
int count=0;
//生产
public synchronized void push(Product product){
if(count==products.length){
//如果缓冲区满了,等待消费者消费
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
products[count]=product;
this.notifyAll();
count++;
}
//消费
public synchronized Product pop(){
if(count==0){
//等待生产者生产
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
count--;
Product product1 = products[count];
this.notifyAll();
return product1;
}
}
上面代码中,就有生产者,消费者,产品,缓冲区。
有一个生产者和一个消费者,生产者生产商品到缓冲区,缓冲区设置了10长度的数组缓冲,当缓冲区满了时就等待消费者消费,如果缓冲区为0就等生产者生产。其实这里我码的时候还出现一个尴尬的问题。
public synchronized Product pop(){
if(count==0){
//等待生产者生产
try {
Thread.sleep();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
count--;
Product product1 = products[count];
return product1;
}
```
我开始使用的Thread类中的sleep()方法让线程等待,这个巨傻帽的问题- -,因为两个方法都是sync同步锁锁住了的,sleep()在休眠的时候是不会释放对象锁的,所以就等于白等。所以得用wait()方法,将锁释放后再等待,等另一方进去后再被notifyAll()唤醒。
这个方法主要就是避免消费者直接去使用生产者的数据产生的安全问题。