案例一:有两个线程,一个生产者线程,一个消费者线程
假设有一个产品类(实体类),我们通过生产者线程对其值(属性)进行设置,通过消费者线程再读取其设置的值。
要达到的最终效果是:每次生产一个,消费一个。
分五步来实现:
第一步,两个线程正确操作同一个数据源
第二步,采用循环实现数据的交替变化(数据在两个产品之间切换),来更明显发现上述程序存在的问题(把潜在问题放大化)
第三步,采用同步机制来解决上述的问题
第四步,考虑如何达到读一个写一个的效果(java的等待唤醒机制 wait notiy)
生产一个消费一个
生产者,发现有产品,就休息一下,等待消费者消费,等消费完,继续生产
消费者,发现没有产品,就休息以下,等待生产者进行生产,生产完了,继续消费
第五步,更加合理的优化写法
把原先是否需要wait()的控制由生产者线程(或消费者线程)搬到了产品类里面的同步方法中,调用者只管调用,不需要关注同步的处理细节,就好比下面的理解来看
生产者(厨师)
产品类(服务员-手握决定权)
消费者(顾客)
一个生产者一个消费者
public class Test01 {
public static void main(String[] args) {
Phone phone = new Phone();
Producer producer = new Producer(phone);
Consumer consumer = new Consumer(phone);
producer.start();
consumer.start();
}
}
//手机类
public class Phone {
private String brand;
private double price;
private boolean store;
public Phone() {}
public Phone(String brand, int 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(int price) {
this.price = price;
}
public boolean isStore() {
return store;
}
public void setStore(boolean store) {
this.store = store;
}
}
//生产者线程
public class Producer extends Thread{
private Phone phone;
public Producer(Phone phone) {
this.phone = phone;
}
@Override//重写run方法
public void run() {
boolean flag=true;
while(true) {
synchronized (phone) {
if(phone.isStore()==true) {
try {
phone.wait();
} catch (InterruptedException e) {}
}
if(flag) {
phone.setBrand("三星");
phone.setPrice(4999);
}else {
phone.setBrand("小米");
phone.setPrice(1999);
}
flag=!flag;
phone.setStore(true);
phone.notify();
}
}
}
}
//消费者线程
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()==false) {
try {
phone.wait();
} catch (InterruptedException e) {}
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {}
System.out.println(phone.getBrand()+"---"+phone.getPrice());
phone.setStore(false);
phone.notify();
}
}
}
}
多个生产者多个消费者
public class Test01 {
public static void main(String[] args) {
Phone phone = new Phone();
Producer producer1 = new Producer(phone);
Producer producer2 = new Producer(phone);
Consumer consumer1 = new Consumer(phone);
Consumer consumer2 = new Consumer(phone);
producer1.start();
producer2.start();
consumer1.start();
consumer2.start();
}
}
//手机类
public class Phone {
private String brand;
private double price;
private boolean store;
public Phone() {
}
public Phone(String brand, int 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(int price) {
this.price = price;
}
public boolean isStore() {
return store;
}
public void setStore(boolean store) {
this.store = store;
}
}
//生产者
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()==true) {
try {
phone.wait();
} catch (InterruptedException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
}
if(flag) {
phone.setBrand("三星");
phone.setPrice(4999);
}else {
phone.setBrand("小米");
phone.setPrice(1999);
}
flag=!flag;
phone.setStore(true);
phone.notifyAll();
}
}
}
}
//消费者
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()==false) {
try {
phone.wait();
} catch (InterruptedException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
System.out.println(phone.getBrand()+"---"+phone.getPrice());
phone.setStore(false);
phone.notifyAll();
}
}
}
}
-
案例二:
实际上,准确说应该是“生产者-消费者-仓储”模型,离开了仓储,生产者消费者模型就显得没有说服力了。
对于此模型,应该明确一下几点:
1、生产者仅仅在仓储未满时候生产,仓满则停止生产。
2、消费者仅仅在仓储有产品时候才能消费,仓空则等待。
3、当消费者发现仓储没产品可消费时候会通知生产者生产。
4、生产者在生产出可消费产品时候,应该通知等待的消费者去消费。
生产者消费者仓储模式
public class Test01 {
public static void main(String[] args) {
//生产者-仓储-消费者
Store store = new Store();
Producer producer = new Producer(store);
Consumer consumer = new Consumer(store);
producer.start();
consumer.start();
}
}
//仓储
public class Store {
private int max = 20;//最大容量
private int num = 0;//最小容量
//入库
public void push() {
synchronized (this) {
if(num>=max) {
try {
this.wait();
} catch (InterruptedException e) {
}
}
num++;
System.out.println("入库"+num);
this.notify();
}
}
//出库
public void pop() {
synchronized (this) {
if(num<=0) {
try {
this.wait();
} catch (InterruptedException e) {
}
}
num--;
System.out.println("出库:"+num);
this.notify();
}
}
}
//生产者
public class Producer extends Thread{
private Store store;
public Producer(Store store) {
this.store=store;
}
@Override
public void run() {
while(true) {
store.push();
}
}
}
//消费者
public class Consumer extends Thread{
private Store store;
public Consumer(Store store) {
this.store = store;
}
@Override
public void run() {
while(true) {
store.pop();
}
}
}
卖包子模型-LinkedList先进先出
public class Test01 {
public static void main(String[] args) {
Store store = new Store();
Producer producer1 = new Producer(store);
Producer producer2 = new Producer(store);
Producer producer3 = new Producer(store);
Consumer consumer1 = new Consumer(store);
Consumer consumer2 = new Consumer(store);
Consumer consumer3 = new Consumer(store);
Consumer consumer4 = new Consumer(store);
Consumer consumer5 = new Consumer(store);
Consumer consumer6 = new Consumer(store);
producer1.start();
producer2.start();
producer3.start();
consumer1.start();
consumer2.start();
consumer3.start();
consumer4.start();
consumer5.start();
consumer6.start();
}
}
包子类
public class BaoZi {
private String time;
public BaoZi() {}
public BaoZi(String time) {
this.time = time;
}
/**
* @return time
*/
public String getTime() {
return time;
}
/**
* @param time 要设置的 time
*/
public void setTime(String time) {
this.time = time;
}
/* (非 Javadoc)
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return "包子日期" + time;
}
}
仓储
public class Store {
private int max = 20;//最大容量
private int num = 0;//最小容量
private LinkedList<BaoZi> list = new LinkedList<>();
//入库
public void push() {
synchronized (this) {
while(num>=max) {
try {
this.wait();
} catch (InterruptedException e) {
}
}
num++;
System.out.println("入库"+num);
SimpleDateFormat sdf = new SimpleDateFormat("yyyy MM dd HH:mm:ss");
String time = sdf.format(new Date());
BaoZi baoZi = new BaoZi(time);
list.add(baoZi);
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
this.notifyAll();
}
}
//出库
public void pop() {
synchronized (this) {
while(num<=0) {
try {
this.wait();
} catch (InterruptedException e) {
}
}
num--;
System.out.println("出库:"+num+list.removeFirst());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
this.notifyAll();
}
}
}
生产者
public class Producer extends Thread{
private Store store;
public Producer(Store store) {
this.store=store;
}
@Override
public void run() {
while(true) {
store.push();
}
}
}
消费者
public class Consumer extends Thread{
private Store store;
public Consumer(Store store) {
this.store = store;
}
@Override
public void run() {
while(true) {
store.pop();
}
}
}