多线程模型
生产者消费者模型要用到对象监视器,先看扩展。
生产者消费者模型
套用生产者消费者模型的情况:多线程操作同一个资源,并且多个线程的功能不一样,就用生产者消费者模型。
生产者消费者模型理解图:
1、一个生产者一个消费者
//需求:生产一个消费一个
public class Phone {
private String brand;
private double price;
private boolean isStore;//是否有库存
public Phone() {}
public Phone(String brand, double price) {
this.brand = brand;
this.price = price;
}
//TODO补全get set toString。。。。
}
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 {
phone.wait();//对象监视器,等待,进入阻塞,wait来自Object 会自动释放锁资源
//sleep是Thread的,不会释放锁资源
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(phone);
phone.setStore(false);
phone.notify();//唤醒对象监视器中记录的第一个线程
}
}
}
}
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()){//有库存
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();//
}
}
}
}
public static void main(String[] args) {
Phone phone = new Phone();
Producer p = new Producer(phone);
Consumer c = new Consumer(phone);
p.start();
c.start();
}
2、多个生产者多个消费者
//需求:生产一个消费一个
public class Phone{}//和上面一样
public class Consumer extends Thread{
private Phone phone;
//TODO构造方法。。。
@Override
public void run() {
while (true){
synchronized(phone){
while (!phone.isStore()){//没库存//----变
try {
phone.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(phone);
phone.setStore(false);
phone.notifyAll();//----变
}
}
}
}
//如果这两个地方没变,会出现各种奇奇怪怪的脏数据,可以自己考虑下为什么会出现这些鬼东西。
//注:wait()等待唤醒后是接着wait往下执行的
public class Producer extends Thread{}//变化的地方和Consumer一样
public static void main(String[] args) {
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();
}
仓储模型
生产者消费者模型的一种
1.一个生产者一个消费者
public class Cake {
private String brand;
private String dataTime;
//TODO 有参无参构造 get set toString。。。
}
public class Store {
//蛋糕容器
private LinkedList<Cake> list = new LinkedList<>();
//最大容量
private int maxCapacity = 20;
//当前容量
private int currentCapacity;
//入库
public void push(Cake cake){
synchronized (this) {
if(currentCapacity >= maxCapacity){
try {
this.wait();//
} catch (InterruptedException e) {
e.printStackTrace();
}
}
list.add(cake);
currentCapacity++;
System.out.println("入库,当前容量为:" + currentCapacity);
this.notify();//
}
}
//出库
public void pop(){
synchronized (this) {
if(currentCapacity <= 0){//------------变
try {
this.wait();//
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Cake cake = list.removeFirst();
currentCapacity--;
System.out.println("出库,当前容量为:" + currentCapacity + " -- " + cake);
this.notify();//-------变
}
}
}
public class Producer extends Thread{
private Store store;
public Producer(Store store) {this.store = store;}
@Override
public void run() {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
while(true){
Cake cake = new Cake("桃李面包", sdf.format(new Date()));
store.push(cake);
}
}
}
public class Consumer extends Thread{
private Store store;
public Consumer(Store store) {this.store = store;}
@Override
public void run() {
while(true){store.pop();}
}
}
public static void main(String[] args) {
Store store = new Store();
Producer p = new Producer(store);
Consumer c = new Consumer(store);
p.start();
c.start();
}
2、多个生产者多个消费者
public class Store{}//if 和notify变化
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();
}
扩展:对象监视器
前面phone.wait();
和phone.notify();
中的phone是对象监视器,而对象监视器可以是很多东西,像this、Consumer这些都可以是。但要在两个不同的线程里互相唤醒对方,就必须用相同的监视器。wait()
是将当前线程阻塞,并且将其记录到监视器中(监视器不同自然就不知道要唤醒谁),notify()
是将线程从阻塞状态唤醒(唤醒1个),进入就绪状态。notifyAll()
是唤醒全部。
一般来说,安全锁用什么,对象监视器就用什么。