生产者消费者模型
定义
生产者消费者是一个多线程同步问题的经典模型,也是线程通信的经典模型。
线程通信
不同的线程执行不同的任务,如果这些任务有某种关系,各个线程必须要能够通信,从而完成工作。
模型描述
生产者生成一定量的数据放到缓冲区中,然后重复此过程;与此同时,消费者也在缓冲区消耗这些数据。
生产者和消费者之间必须保持同步:
要保证生产者不会在缓冲区满时放入数据,消费者也不会在缓冲区空时消耗数据。不够完善的解决方法容易出现死锁的情况,此时进程都在等待唤醒。
模型分析
- 消费者和生产者同时访问该内存,那么肯定通过多线程实现模型。
- 采用某种机制保护生产者和消费者之间的同步。
保证同一资源被多个线程并发访问时的完整性。
常用的同步方法是采用信号或加锁机制,保证资源在任意时刻至多被一个线程访问。
创建数据类
我们首先创建数据类,来模拟生产者生产和消费者消费的产品。
public class Data {
int number = 0;
}
使用synchronized修饰
多线程并发同一资源,要把它们的方法用synchronized修饰保证它们生产和消费不同时进行。
wait() / notify()方法
wait()方法:执行该方法的对象释放同步锁,JVM把该线程存放到等待池中,等待其他线程唤醒。
notify()方法:唤醒在等待池中的等待的任意一个线程,把线程转移到锁池中。
当生产者生产商品满时,停止执行,放弃锁进入等待,并通知消费者进行消费。
当消费者消费商品完时,停止执行,放弃锁进入等待,并通知生产者进行生产。
设置线程休眠
在生产者线程和消费者线程中,设置线程线程休眠,保证线程间通信的正常进行。
创建线程仓库
在生产者线程和消费者线程中,储存线程。
代码如下所示
创建数据类
public class Data {
int number = 0;
}
生产者线程
public class Producer implements Runnable{
// 保存数据的仓库
private List<Data> listData;
private int MAX = 10;
public Producer(List<Data> listData) {
this.listData = listData;
}
// 生命周期:
@Override
public void run() {
// TODO Auto-generated method stub
while(true){
// 同步代码快:synchronized(监视器/锁){ 需要同步的代码块..}
// 监视器:任何一个对象都可以作为监视器使用
// 在多线程状态下,所有的线程使用的监视器必须是同一个
synchronized(listData){
if(listData.size() < MAX){
// 休眠
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// 生产者向仓库添加数据
listData.add(new Data());
System.out.println(Thread.currentThread().getName()+":生产产品,剩余产品"+listData.size());
// 唤醒线程
listData.notify();
}else{
//休眠
try {
System.out.println("仓库已满!!!");
// 线程休眠
listData.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
}
消费者线程
public class Consumer implements Runnable{
private List<Data> listData;
public Consumer(List<Data> listData) {
this.listData = listData;
}
@Override
public void run() {
// TODO Auto-generated method stub
while(true){
// 同步代码快:synchronized(监视器/锁){ 需要同步的代码块..}
// 监视器:任何一个对象都可以作为监视器使用
// 在多线程状态下,所有的线程使用的监视器必须是同一个
synchronized(listData){
if(listData.size() > 0 ){
// 休眠
try {
Thread.sleep(300);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
listData.remove(0);
System.out.println(Thread.currentThread().getName()+":消费产品,剩余产品"+listData.size());
// 唤醒线程
listData.notify();
}else{
try {
System.out.println("仓库没有产品!!");
// 线程休眠
listData.wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
}
管理者
管理者运行Java主函数
import java.util.ArrayList;
import java.util.List;
public class Manager {
public static void main(String[] args) {
// 创建仓库对象
List <Data> listData = new ArrayList <Data>();
// 生产者
Producer producer = new Producer(listData);
// 消费者
Consumer consumer = new Consumer(listData);
// 启动线程
new Thread(producer,"生产者1:").start();
new Thread(producer,"生产者2:").start();
new Thread(consumer,"消费者:").start();
}
}