生产者与消费者模型简介
生产者和消费者彼此之间不直接沟通,而通过阻塞队列来进行通讯,当生产者生产的商品不足时,生产者开始生产,消费者进行阻塞,当生产者生产充足的商品后,唤醒消费者,进行出售......所以生产者生产完数据之后不会等待消费者处理,直接唤醒阻塞队列中的所有线程,同时自身阻塞,消费者在消费完成后,同时唤醒阻塞队列中的所有线程,自身进行阻塞.......阻塞队列就相当于一个缓冲区,平衡了生产者和消费者的能力
wait()方法
- 方法wait()的作用是使当前执行代码的线程进行等待,wait()方法是Object类的方法,该方法是用来将当前线程置入“预执行队列”中,并且wait()所在的代码处停止执行,知道接到通知或被中断为止
- wait()只能在同步方法或同步代码块中调用,如果调用wait()时,没有适当的锁会抛出异常
- wait()方法执行后,当前线程释放锁,线程与其它线程竞争重新获取锁
notify()方法
- 方法notify()作用是使停止的线程继续运行
- 方法notify()也要在同步方法或同步代码块中调用,该方法是用来通知那些可能等待该对象的对象锁的其他线程,对其发出通知notify,并使它们重新获取该对象的对象锁,如果有多个线程等待,线程规划器随机挑选一个呈wait状态的线程
- 在notify()之后,当前对象不会马上释放对象锁,要等到执行notify()方法的线程将程序执行完,也就使退出同步代码块之后才会释放对象锁
notifyAll()方法
- 同notify()方法,当时他可一次性唤醒阻塞队列所有的线程
注意:每个锁对象有两个队列,一个是就绪队列,一个是阻塞队列,就绪队列存储了将要获得锁的线程,阻塞队列存储了被阻塞的线程,一个线程被唤醒后,才会进入就绪队列,等待CPU的调度,一个线程被wait后,就会进入阻塞队列,等待下一次被唤醒,得到notify通知后只是从等待队列移出来。在移出来的时候,有可能不直接进入就绪队列直接拿到对象锁,但大多情况下是直接进入就绪队列
单生产单消费模型
商品类
package com.lin;
import org.omg.PortableServer.THREAD_POLICY_ID;
/**
* Description:
* Author: llf
* Created in 2019/8/5 14:06
*/
public class Goods {
private String goodsName;
private int count;
public Goods() {
}
public synchronized void set(String goodsName) throws InterruptedException {
//当生产者生产产品数量超过5个,则等待阻塞,释放对象锁,由消费者竞争锁
if (this.count>5) {
System.out.println("还有商品库存,等待消费者消费");
wait();
}
this.goodsName=goodsName;
this.count++;
Thread.sleep(1000);
System.out.println("生产"+toString());
//唤醒消费者线程,此时已有商品
notify();
}
public synchronized void get() throws InterruptedException {
当没有商品买了,自身阻塞等待,释放对象锁,等待生产者生产出商品在竞争锁继续运行
if (this.count==0) {
System.out.println("商品已卖完,等待生产者生产");
wait();
}
this.count=this.count-1;
Thread.sleep(1000);
System.out.println("消费"+toString());
//唤醒生产者线程,此时可能会即将没有商品
notify();
}
@Override
public String toString() {
return "Goods{" +
"goodsName='" + goodsName + '\'' +
", count=" + count +
'}';
}
}
生产者
package com.lin;
/**
* Description:
* Author: llf
* Created in 2019/8/5 14:11
*/
public class Producer implements Runnable{
private Goods goods;
public Producer(Goods goods) {
super();
this.goods = goods;
}
@Override
public void run() {
try {
this.goods.set("小黑瓶");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
消费者
package com.lin;
/**
* Description:
* Author: llf
* Created in 2019/8/5 14:11
*/
public class Consumer implements Runnable{
private Goods goods;
public Consumer(Goods goods) {
this.goods = goods;
}
@Override
public void run() {
try {
this.goods.get();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
测试
package com.lin;
import java.util.ArrayList;
import java.util.List;
/**
* Description:
* Author: llf
* Created in 2019/8/5 14:17
*/
public class Main {
public static void main(String[] args) throws InterruptedException {
Goods goods=new Goods();
Thread thread1=new Thread(new Producer(goods),"生产者");
Thread thread2=new Thread(new Consumer(goods),"消费者");
thread1.start();
thread2.start();
}
}
程序运行结果
生产者生产Goods{goodsName='小黑瓶', count=1}
生产者生产Goods{goodsName='小黑瓶', count=2}
生产者生产Goods{goodsName='小黑瓶', count=3}
生产者生产Goods{goodsName='小黑瓶', count=4}
生产者生产Goods{goodsName='小黑瓶', count=5}
生产者生产Goods{goodsName='小黑瓶', count=6}
消费者消费Goods{goodsName='小黑瓶', count=5}
生产者生产Goods{goodsName='小黑瓶', count=6}
还有商品库存,等待消费者消费
消费者消费Goods{goodsName='小黑瓶', count=5}
消费者消费Goods{goodsName='小黑瓶', count=4}
消费者消费Goods{goodsName='小黑瓶', count=3}
消费者消费Goods{goodsName='小黑瓶', count=2}
生产者生产Goods{goodsName='小黑瓶', count=3}
消费者消费Goods{goodsName='小黑瓶', count=2}
消费者消费Goods{goodsName='小黑瓶', count=1}
消费者消费Goods{goodsName='小黑瓶', count=0}
商品已卖完,等待生产者生产
多生产者多消费者模型
商品类
package com.lin;
/**
* Description:
* Author: llf
* Created in 2019/8/5 14:06
*/
public class Goods {
private String goodsName;
private int count;
public Goods() {
}
public synchronized void set(String goodsName) throws InterruptedException {
//若此时商品已充足,不需生产,则循环阻塞所有生产者线程
while (this.count>5) {
System.out.println("还有商品库存,等待消费者消费");
wait();
}
this.goodsName=goodsName;
this.count++;
Thread.sleep(1000);
System.out.print(Thread.currentThread().getName());
System.out.println("生产"+toString());
//已生产商品,唤醒所有线程
notifyAll();
}
public synchronized void get() throws InterruptedException {
//已无商品可买,需要生产者生产,循环阻塞消费者线程
while (this.count==0) {
System.out.println("商品已卖完,等待生产者生产");
wait();
}
this.count=this.count-1;
Thread.sleep(1000);
System.out.print(Thread.currentThread().getName());
System.out.println("消费"+toString());
//可能商品数量不足,唤醒所有线程
notifyAll();
}
@Override
public String toString() {
return "Goods{" +
"goodsName='" + goodsName + '\'' +
", count=" + count +
'}';
}
}
生产者
package com.lin;
/**
* Description:
* Author: llf
* Created in 2019/8/5 14:11
*/
public class Producer implements Runnable{
private Goods goods;
public Producer(Goods goods) {
super();
this.goods = goods;
}
@Override
public void run() {
while(true) {
try {
this.goods.set("小黑瓶");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
消费者
package com.lin;
/**
* Description:
* Author: llf
* Created in 2019/8/5 14:11
*/
public class Consumer implements Runnable{
private Goods goods;
public Consumer(Goods goods) {
this.goods = goods;
}
@Override
public void run() {
while (true) {
try {
this.goods.get();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
测试类
package com.lin;
import java.util.ArrayList;
import java.util.List;
/**
* Description:
* Author: llf
* Created in 2019/8/5 14:17
*/
public class Main {
public static void main(String[] args) throws InterruptedException {
Goods goods=new Goods();
List<Thread> threadList=new ArrayList<Thread>();
for (int i = 0; i <10 ; i++) {
Thread thread1=new Thread(new Producer(goods),"生产者"+i);
threadList.add(thread1);
}
for (int i = 0; i < 6; i++) {
Thread thread2=new Thread(new Consumer(goods),"消费者"+i);
threadList.add(thread2);
}
for (Thread thread:threadList) {
thread.start();
}
}
}
运行结果
生产者0生产Goods{goodsName='小黑瓶', count=1}
生产者0生产Goods{goodsName='小黑瓶', count=2}
生产者0生产Goods{goodsName='小黑瓶', count=3}
生产者0生产Goods{goodsName='小黑瓶', count=4}
生产者0生产Goods{goodsName='小黑瓶', count=5}
生产者0生产Goods{goodsName='小黑瓶', count=6}
消费者5消费Goods{goodsName='小黑瓶', count=5}
消费者3消费Goods{goodsName='小黑瓶', count=4}
消费者3消费Goods{goodsName='小黑瓶', count=3}
消费者3消费Goods{goodsName='小黑瓶', count=2}
消费者3消费Goods{goodsName='小黑瓶', count=1}
消费者4消费Goods{goodsName='小黑瓶', count=0}
商品已卖完,等待生产者生产
商品已卖完,等待生产者生产
商品已卖完,等待生产者生产
商品已卖完,等待生产者生产
生产者9生产Goods{goodsName='小黑瓶', count=1}