线程学习之生产者与消费者问题
生产者与消费者问题是著名的线程同步问题,其描述如下:在一个仓库中,生产者生产物品,消费者消耗物品,但两者不能同时利用该仓库进行生产和消费,而且如果仓库满的话,就不能进行生产,仓库为空就不能进行消费。。。。
在这个时候,我们应该要明白这个仓库就是一个临界区,是不能被多个线程同时进行访问的
java语言实现(简括描述):
1.准备工作(分析)
- 所具有的内容
- 仓库:在仓库类中,它具有的属性是它的容量,还有它的生产与消费方法
- 消费者线程:消费者具有的就是对仓库里的物品进行消费
- 生产者线程:生产者具有的就是对生产仓库里的物品时刻来填充仓库
我们知道在线程在对共享变量进行访问的时候,为了避免多个线程同时进行访问,我们应当对共享变量进行“上锁’,(上锁方式两种,一是直接对方法进行“上锁”,二是对代码块进行“上锁”,因此在这里我们要进行上锁的是对仓库中的变量的操作语句即仓库的消费方法与生产方法(为了简单化,我们在这里设生产者与消费者都只仅有一个)
2.部分主要代码
class WareHouse{
/*
* 在这里假设消费者/生产者都是每次消耗/生产一个物品
*/ static int COUNT = 10; //定义仓库的初始值 static int MAX = 30; //定义仓库容量的最大值 public synchronized void product() {
//生产者生产物品 if(COUNT<MAX) { COUNT++; System.out.println("生产者生产了一个资源"); System.out.println("仓库剩余"+WareHouse.COUNT); this.notifyAll(); //唤起正在等待的线程 } else { try { this.wait(); //当仓库中的剩余数量加上要生产的数量的值大于仓库的容量的时候,就线程进行等待 } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } public synchronized void comsu() {
//消费者消费函数 if(COUNT>0) { COUNT--; System.out.println("消费者消耗了一个资源"); System.out.println("仓库剩余"+WareHouse.COUNT); this.notifyAll(); //唤起正在等待的线程 }else { try { this.wait(); //当消费者要消耗的数量大于仓库中剩余的数量的时候,该线程就进行等待 } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }
//注:wait()方法与notifyAll()之类的方法都只能在被sychronized修饰的方法或者代码块中,否则会出现异常
在使用线程同步的时候,应当尽量避免死锁,例如在这个例子中,比如仓库的最大容量为100,剩余物品为50,但消费者和生产者每次消耗和生产物品的数量为60,然后生产者就一直在等着消费者消耗,消费者在等着生产者生产,两个线程就一直在互相等待,造成死锁。