二十五、生产者消费者问题
作者:互联网
线程通信:
- 应用场景:生产者和消费者问题
- 假设仓库中只能存放一件产品,生产者将生产出来的产品放入仓库﹐消费者将仓库中产品取走消费
- 如果仓库中没有产品,则生产者将产品放入仓库,否则停止生产并等待,直到仓库中的产品被消费者取走为止
- 如果仓库中放有产品,则消费者可以将产品取走消费﹐否则停止消费并等待,直到仓库中再次放入产品为止
- 分析:这是一个线程同步问题,生产者和消费者共享同一个资源,并且生产者和消费者之间相互依赖,互为条件
-
对于生产者,没有生产产品之前,要通知消费者等待.而生产了产品之后﹐又需要马上通知消费者消费
-
对于消费者﹐在消费之后,要通知生产者已经结束消费
-
需要生产新的产品以供消费.在生产者消费者问题中
-
仅有synchronized是不够的
-
synchronized可阻止并发更新同一个共享资源,实现了同步
-
synchronized不能用来实现不同线程之间的消息传递(通信)
-
-
- Java提供了几个方法解决线程之间的通信问题。注意:均是Object类的方法,都只能在同步方法或者同步代码块中使用,否则会抛出异常lllegalMonitorStateException
方法名 | 作用 |
wait() | 表示线程一直等待﹐直到其他线程通知,与sleep不同,会释放锁 |
wait(long timeout) | 指定等待的毫秒数 |
notify() | 唤醒一个处于等待状态的线程 |
notifyAll() | 唤醒同一个对象上所有调用wait()方法的线程﹐优先级别高的线程优先调度 |
- 并发协作模型“生产者/消费者模式”:生产者将生产好的数据放入缓冲区,消费者从缓冲区拿出数据
- 生产者:负责生产数据的模块(可能是方法﹐对象﹐线程﹐进程);
- 消费者:负责处理数据的模块(可能是方法﹐对象,线程,进程);
- 缓冲区:消费者不能直接使用生产者的数据﹐他们之间有个“缓冲区;
-
-
- 解决方式1:管程法(缓冲区)
-
public class ProducersAndConsumers {
public static void main(String[] args) {
SynContainer synContainer = new SynContainer();
Producers p = new Producers(synContainer);
Consumers c = new Consumers(synContainer);
new Thread(p).start();
new Thread(c).start();
}
}
//生产者
class Producers implements Runnable {
SynContainer synContainer;
public Producers(SynContainer synContainer) {
this.synContainer = synContainer;
}
@Override
public void run() {
for (int i = 1; i <= 100; i++) {
try {
synContainer.push(i);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
//消费者
class Consumers implements Runnable {
SynContainer synContainer;
public Consumers(SynContainer synContainer) {
this.synContainer = synContainer;
}
@Override
public void run() {
for (int i = 1; i <= 100; i++) {
try {
synContainer.pop(i);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
//产品
class Chicken {
int id;
public Chicken(int id) {
this.id = id;
}
}
//缓冲区
class SynContainer {
Chicken[] chickens = new Chicken[10];
int count = 0;
//生产
public synchronized void push(int i) throws InterruptedException {
while (chickens.length == count) {
this.wait();
}
Chicken chicken = new Chicken(i);
chickens[count] = chicken;
count++;
System.out.println("生产第" + i + "只鸡");
this.notifyAll();
}
//消费
public synchronized void pop(int i) throws InterruptedException {
while (count == 0) {
this.wait();
}
//模拟延迟消费
Thread.sleep(100);
count--;
System.out.println("消费第" + i + "只鸡");
Chicken chicken = chickens[count];
this.notifyAll();
}
}
-
-
- 解决方式2:信号灯法(标志位)
-
public class ProducersAndConsumers2 {
public static void main(String[] args) {
Product product = new Product();
Producers2 p = new Producers2(product);
Consumers2 c = new Consumers2(product);
new Thread(p).start();
new Thread(c).start();
}
}
//生产者
class Producers2 implements Runnable {
Product product;
public Producers2(Product product) {
this.product = product;
}
@Override
public void run() {
for (int i = 1; i <= 100; i++) {
try {
product.push(i);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
//消费者
class Consumers2 implements Runnable {
Product product;
public Consumers2(Product product) {
this.product = product;
}
@Override
public void run() {
for (int i = 1; i <= 100; i++) {
try {
product.pop(i);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
//缓冲区
class Product {
//产品
int id;
//标志位
boolean flag = false;
//生产
public synchronized void push(int id) throws InterruptedException {
while (flag) {
this.wait();
}
this.flag = !this.flag;
System.out.println("生产了" + id + "号");
this.notifyAll();
}
//消费
public synchronized void pop(int id) throws InterruptedException {
while (!flag) {
this.wait();
}
this.flag = !this.flag;
System.out.println("消费了" + id + "号");
this.notifyAll();
}
}
标签:消费者,生产者,线程,二十五,new,public,synContainer 来源: https://www.cnblogs.com/epiphany8/p/16293446.html