生产者消费者模型与仓储模型案例解析
目录
1.生产者消费者模型
1.1 单个生产者单个消费者
1.1.1知识点
-
生产者消费者模型:一种常见的并发模式,用于协调生产者和消费者之间的工作流程,确保数据的有效生产和消费。
-
Java中的线程同步和通信:使用
synchronized关键字和wait/notify方法来控制线程间的协调和通信。
1.1.2案例分析
-
产品类 (Phone): 拥有品牌 (brand) 和价格 (price) 属性。
-
生产者线程 (Producer): 负责生产产品,即设置Phone的品牌和价格。
-
消费者线程 (Consumer): 负责消费产品,即读取Phone的品牌和价格。
1.1.3代码概述
-
Phone类
-
属性:brand(品牌)、price(价格)、store(库存标志)。
-
方法:getters、setters、toString()。
-
-
Producer类
-
在
run方法中,交替生产华为和小米手机。 -
使用
synchronized来确保线程安全。 -
当存在库存时,使用
wait方法让生产者线程等待。
-
-
Consumer类
-
在
run方法中,循环消费手机。 -
使用
synchronized来确保线程安全。 -
当无库存时,使用
wait方法让消费者线程等待。 -
消费后打印手机信息,并通知生产者继续生产。
-
1.1.4特点
-
线程间的协作:通过
wait和notify方法实现线程间的协作。 -
控制生产消费节奏:保证生产一个消费一个的节奏,避免资源浪费和冲突。
-
解决脏数据问题:通过线程同步机制,确保数据的准确性和一致性。 这个案例是生产者消费者问题的典型应用,展示了如何在Java中使用线程同步和通信机制来解决并发问题。
1.1.5代码
package com.qf.producer_consumer_01;
public class Test01 {
/**
* 知识点:生产者消费者模型 - 单个生产者单个消费者
*
* 分析:
* 产品类 - Phone:属性(brand,price)
* 生产者线程 - Producer
* 消费者线程 - Consumer
* 最终的目的:生产一个、消费一个
*
* 步骤:
* 1.多个线程(生产者线程、消费者线程)操作同一个资源(产品类的对象)
* 2.多个产品之间来回切换(华为 <--> 小米)
* null -- 0.0
* 华为 -- 0.0
* 小米 -- 3999
* 华为 -- 1999
* 脏数据的解决思路:加锁
* 3.生产一个消费一个
*
*/
public static void main(String[] args) {
//brand - null
//price - 0.0
Phone phone = new Phone();
Producer p = new Producer(phone);
Consumer c = new Consumer(phone);
p.start();
c.start();
}
}
package com.qf.producer_consumer_01;
//产品类
public class Phone {
private String brand;
private double price;
private boolean store;
public Phone() {
}
public Phone(String brand, double price) {
this.brand = brand;
this.price = price;
}
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public boolean isStore() {
return store;
}
public void setStore(boolean store) {
this.store = store;
}
@Override
public String toString() {
return "Phone [brand=" + brand + ", price=" + price + "]";
}
}
package com.qf.producer_consumer_01;
//生产者线程
public class Producer extends Thread{
private Phone phone;
public Producer(Phone phone) {
this.phone = phone;
}
@Override
public void run() {
boolean flag = true;
while(true){
synchronized(phone){
if(phone.isStore()){//有库存
//等待
//1.将当前线程记录在对象监视器中(记录当前线程进入到阻塞状态)
//2.释放锁资源(解锁)
//3.当前线程进入到阻塞状态
try {
phone.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if(flag){
phone.setBrand("华为");
phone.setPrice(3999);
}else{
phone.setBrand("小米");
phone.setPrice(1999);
}
flag = !flag;
phone.setStore(true);
//唤醒:唤醒的是对象监视器中随机一个等待的线程,唤醒的线程进入到就绪态
phone.notify();
}
}
}
}
package com.qf.producer_consumer_01;
//消费者线程
public class Consumer extends Thread{
private Phone phone;
public Consumer(Phone phone) {
this.phone = phone;
}
@Override
public void run() {
while(true){
synchronized(phone){
if(!phone.isStore()){//没有库存
try {
//等待:
//1.将当前线程记录在对象监视器中(记录当前线程进入到阻塞状态)
//2.释放锁资源(解锁)
//3.当前线程进入到阻塞状态
phone.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(phone.getBrand() + " -- " + phone.getPrice());
phone.setStore(false);
//唤醒:唤醒的是对象监视器中随机一个等待的线程,唤醒的线程进入到就绪态
phone.notify();
}
}
}
}
1.2 多个生产者多个消费者
线程同步
在多线程环境中,确保数据一致性和避免线程间的冲突是必须的。Java中,synchronized关键字用于在对象上加锁,确保一次只有一个线程可以访问该对象的同步代码块或方法。
线程通信
wait()、notify()和notifyAll()是Object类的一部分,用于线程间的通信。当一个线程调用共享对象的wait()方法时,它进入等待状态直到另一个线程调用该对象的notify()或notifyAll()方法。
关键词解释
-
synchronized: Java关键字,用于创建同步代码块或方法,确保多个线程访问共享资源时的同步和数据一致性。
-
wait(): 当一个线程执行到
wait()方法时,它会释放持有的锁并进入等待状态,直到被notify()或notifyAll()唤醒。 -
notify(): 用于唤醒在同一个对象上调用
wait()方法而进入等待状态的单个线程。 -
notifyAll(): 用于唤醒所有在同一个对象上调用
wait()方法而进入等待状态的线程。在多个生产者和消费者的场景中,使用notifyAll()可以避免某些线程永远处于等待状态(即线程假死)。
代码
synchronized用于确保在生产或消费手机对象时不会有多个线程同时操作。wait()和notifyAll()用于控制生产者和消费者之间的协作,其中wait()使当前线程等待,直到另一个线程调用notifyAll()`。这样,就可以在生产者和消费者之间有效地协调工作,避免数据不一致或资源浪费。
package com.qf.producer_consumer_02;
public class Test01 {
/**
* 知识点:生产者消费者模型 - 多个生产者多个消费者
*
* 分析:
* 产品类 - Phone:属性(brand,price)
* 生产者线程 - Producer
* 消费者线程 - Consumer
* 最终的目的:生产一个、消费一个
*
* 步骤:
* 1.多个线程(生产者线程、消费者线程)操作同一个资源(产品类的对象)
* 2.多个产品之间来回切换(华为 <--> 小米)
* null -- 0.0
* 华为 -- 0.0
* 小米 -- 3999
* 华为 -- 1999
* 脏数据的解决思路:加锁
* 3.生产一个消费一个
*
*/
public static void main(String[] args) {
//brand - null
//price - 0.0
Phone phone = new Phone();
Producer p1 = new Producer(phone);
Producer p2 = new Producer(phone);
Consumer c1 = new Consumer(phone);
Consumer c2 = new Consumer(phone);
p1.start();
p2.start();
c1.start();
c2.start();
}
}
package com.qf.producer_consumer_02;
//产品类
public class Phone {
private String brand;
private double price;
private boolean store;
public Phone() {
}
public Phone(String brand, double price) {
this.brand = brand;
this.price = price;
}
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public boolean isStore() {
return store;
}
public void setStore(boolean store) {
this.store = store;
}
}
package com.qf.producer_consumer_02;
//消费者线程
public class Consumer extends Thread{
private Phone phone;
public Consumer(Phone phone) {
this.phone = phone;
}
@Override
public void run() {
while(true){
synchronized(phone){
while(!phone.isStore()){//没有库存
try {
//等待:
//1.将当前线程记录在对象监视器中(记录当前线程进入到阻塞状态)
//2.释放锁资源(解锁)
//3.当前线程进入到阻塞状态
phone.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(phone.getBrand() + " -- " + phone.getPrice());
phone.setStore(false);
//唤醒:唤醒对象监视器中所有的线程
phone.notifyAll();
}
}
}
}
package com.qf.producer_consumer_02;
//生产者线程
public class Producer extends Thread{
private Phone phone;
public Producer(Phone phone) {
this.phone = phone;
}
@Override
public void run() {
boolean flag = true;
while(true){
synchronized(phone){
while(phone.isStore()){//有库存
//等待
//1.将当前线程记录在对象监视器中(记录当前线程进入到阻塞状态)
//2.释放锁资源(解锁)
//3.当前线程进入到阻塞状态
try {
phone.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if(flag){
phone.setBrand("华为");
phone.setPrice(3999);
}else{
phone.setBrand("小米");
phone.setPrice(1999);
}
flag = !flag;
phone.setStore(true);
//唤醒:唤醒对象监视器中所有的线程
phone.notifyAll();
}
}
}
}
2.仓储模型
2.1 一个生产者一个消费者
2.1.1 知识点
-
仓储模型:一种协调生产者和消费者之间生产和消费的模式。
-
Java中的线程同步和通信:使用
synchronized关键字和wait/notify方法来控制线程间的同步和通信。
2.1.2 案例分析
-
产品类 (Cake): 具有品牌(brand)、价格(price)和时间(datetime)属性。
-
仓库类 (Store): 管理产品的仓储,包括最大容量(maxCapacity)、当前容量(curCapacity)和产品列表(list)。
-
生产者线程 (Producer): 生产产品并存入仓库。
-
消费者线程 (Consumer): 从仓库中取出并消费产品。
2.1.3 代码概述
-
Store类
-
使用
synchronized实现线程同步。 -
push方法:当仓库容量满时,使用wait方法使生产者等待;否则,生产产品并通知消费者。 -
pop方法:当仓库为空时,使用wait方法使消费者等待;否则,消费产品并通知生产者。
-
-
Cake类
-
定义产品的属性和方法。
-
-
Producer类
-
循环生产产品并调用
push方法存入仓库。
-
-
Consumer类
-
循环从仓库中取出并消费产品。
-
2.1.4代码
package com.qf.store_01;
public class Test01 {
/**
* 知识点:仓储模型 - 一个生产者一个消费者
*
* 分析:
* 产品类 - Cake(brand、price、datetime)
* 仓库类 - Store(maxCapacity、curCapacity、list)
* 生产者线程 - Producer
* 消费者线程 - Consumer
* 注意:先生产的先卖出 -- 队列模式
*
* 经验:对象监视器如何选择?
* 锁对象
*
*/
public static void main(String[] args) {
Store store = new Store();
Producer p = new Producer(store);
Consumer c = new Consumer(store);
p.start();=
c.start();
}
}
package com.qf.store_01;
import java.util.LinkedList;
public class Store {
private static final int DEFAULT_INIT_CAPACITY = 20;
private int maxCapacity;
private int curCapacity;
private LinkedList<Cake> list;
public Store() {
maxCapacity = DEFAULT_INIT_CAPACITY;
list = new LinkedList<>();
}
public Store(int maxCapacity) {
this.maxCapacity = maxCapacity;
list = new LinkedList<>();
}
//入库
public synchronized void push(Cake cake){
if(curCapacity >= maxCapacity){
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
list.add(cake);
curCapacity++;
System.out.println("入库,当前库存为:" + curCapacity);
this.notify();
}
//出库
public synchronized Cake pop(){
if(curCapacity <= 0){
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Cake cake = list.removeFirst();
curCapacity--;
System.out.println("出库,当前的库存为:" + curCapacity + ",卖出的产品是:" + cake);
this.notify();
return cake;
}
}
package com.qf.store_01;
public class Cake {
private String brand;
private double price;
private String datetime;
public Cake() {
}
public Cake(String brand, double price, String datetime) {
this.brand = brand;
this.price = price;
this.datetime = datetime;
}
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public String getDatetime() {
return datetime;
}
public void setDatetime(String datetime) {
this.datetime = datetime;
}
@Override
public String toString() {
return "Cake [brand=" + brand + ", price=" + price + ", datetime=" + datetime + "]";
}
}
package com.qf.store_01;
public class Consumer extends Thread{
private Store store;
public Consumer(Store store) {
this.store = store;
}
@Override
public void run() {
while(true){
store.pop();
}
}
}
package com.qf.store_01;
import java.time.LocalDateTime;
public class Producer extends Thread{
private Store store;
public Producer(Store store) {
this.store = store;
}
@Override
public void run() {
while(true){
Cake cake = new Cake("桃李蛋糕", 2.5, LocalDateTime.now().toString());
store.push(cake);
}
}
}
2.2 多个生产者多个消费者
2.2.1 知识点
-
与2.1相同,但在多个生产者和消费者的情况下,线程同步和通信更为复杂。
2.2.2 案例分析
-
与2.1相同,但有多个生产者和消费者。
2.2.3 代码概述
-
Store类
-
与2.1相同,但在
push和pop方法中使用notifyAll而非notify,以唤醒所有等待的线程。
-
-
Producer类和Consumer类
-
与2.1相同,但存在多个实例。
-
知识点拓展
-
synchronized: Java关键字,用于线程同步,确保一次只有一个线程可以访问共享资源。
-
wait(): 使当前线程等待,直到另一个线程调用
notify()或notifyAll()。 -
notify(): 唤醒在该对象监视器上等待的单个线程。
-
notifyAll(): 唤醒在该对象监视器上等待的所有线程,通常在多个生产者和消费者的场景中使用。
2.2.4代码
package com.qf.store_02;
public class Test01 {
/**
* 知识点:仓储模型 - 多个生产者多个消费者
*
* 分析:
* 产品类 - Cake(brand、price、datetime)
* 仓库类 - Store(maxCapacity、curCapacity、list)
* 生产者线程 - Producer
* 消费者线程 - Consumer
* 注意:先生产的先卖出 -- 队列模式
*
* 经验:对象监视器如何选择?
* 锁对象
*
*/
public static void main(String[] args) {
Store store = new Store();
Producer p1 = new Producer(store);
Producer p2 = new Producer(store);
Consumer c1 = new Consumer(store);
Consumer c2 = new Consumer(store);
p1.start();
p2.start();
c1.start();
c2.start();
}
}
package com.qf.store_02;
public class Cake {
private String brand;
private double price;
private String datetime;
public Cake() {
}
public Cake(String brand, double price, String datetime) {
this.brand = brand;
this.price = price;
this.datetime = datetime;
}
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public String getDatetime() {
return datetime;
}
public void setDatetime(String datetime) {
this.datetime = datetime;
}
@Override
public String toString() {
return "Cake [brand=" + brand + ", price=" + price + ", datetime=" + datetime + "]";
}
}
package com.qf.store_02;
import java.util.LinkedList;
public class Store {
private static final int DEFAULT_INIT_CAPACITY = 20;
private int maxCapacity;
private int curCapacity;
private LinkedList<Cake> list;
public Store() {
maxCapacity = DEFAULT_INIT_CAPACITY;
list = new LinkedList<>();
}
public Store(int maxCapacity) {
this.maxCapacity = maxCapacity;
list = new LinkedList<>();
}
//入库
public synchronized void push(Cake cake){
while(curCapacity >= maxCapacity){
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
list.add(cake);
curCapacity++;
System.out.println("入库,当前库存为:" + curCapacity);
this.notifyAll();
}
//出库
public synchronized Cake pop(){
while(curCapacity <= 0){
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Cake cake = list.removeFirst();
curCapacity--;
System.out.println("出库,当前的库存为:" + curCapacity + ",卖出的产品是:" + cake);
this.notifyAll();
return cake;
}
}
package com.qf.store_02;
public class Consumer extends Thread{
private Store store;
public Consumer(Store store) {
this.store = store;
}
@Override
public void run() {
while(true){
store.pop();
}
}
}
package com.qf.store_02;
import java.time.LocalDateTime;
public class Producer extends Thread{
private Store store;
public Producer(Store store) {
this.store = store;
}
@Override
public void run() {
while(true){
Cake cake = new Cake("桃李蛋糕", 2.5, LocalDateTime.now().toString());
store.push(cake);
}
}
}
更多推荐


所有评论(0)