线程学习(三)---生产消费模型
什么是生产消费模型
生产消费模型图例
生产消费模型解释
由图例可知,生产消费模型由三个部分组成生产者、消费者、缓冲容器。生产者线程不断产生数据并存储在缓冲容器中,而消费者不断从缓冲容器中获取数据进行操作。如果缓冲容器满那么就让生产者进入等待状态,等待消费者取出数据操作之后再唤醒生产者;如果缓冲容器为空则让消费者进入等待状态,等待生产者生产之后再唤醒消费者。生产者与消费者之前并没有直接接触进行数据传递,而是通过中间的缓冲容器来进行数据取用。这样能平衡生产、消费者的数据处理能力,避免资源产出过剩和线程闲置过多的情况来减少资源浪费。
wait()/notify() notifyAll()与sleep()的区别
线程生命周期图分析
sleep()方法
- sleep()是Thread类的静态方法,无法改变线程持有锁的状态
- sleep()它能在任何地方使用但是需要捕捉异常。
- 使用sleep()方法会让线程暂时释放该线程对cpu的占用但是不会释放它对锁的持有,也就是说当sleep()规定的睡眠时间结束之后该线程就能再次进入就绪状态等待获取cpu的占用。
wait()、notify()、notifyAll()方法
- wait()/notify()以及notifyAll()都是Object类的方法,任何对象都有这个方法,且能改变线程持有其锁的状态。
- wait()、notify()、notifyAll()需要在同步块或者同步方法中使用,因为每个对象都有一个锁,只有当线程拿到锁之后才能访问该对象而同步方法和同步块可以实现与对象锁的交互,这样便能使wait()、notify()、notifyAll()作用于相应对象的锁而不出错。
- 使用wait()方法的同时会同时放弃对cpu的占用和放弃访问对象的锁进入等待池。进入等待池后只能等到持有该线程锁的某个线程调用notify()/notifyAll方法将它唤醒进入锁池,当这个线程获取到执行对象的锁之后才能再次进入就绪状态
简单来说就像你去需要预约的餐厅吃饭,sleep()就相当于你对经理说保留这个位置去处理一些事情再来 吃,你办完事情了过来马上能点餐;而wait()则是你走了不保留这个位置,那么你再来吃饭的话就需要使用notify()/notifyAll()预约这个位置,当你预约成功后你之前的顾客用餐完毕你才能上桌点餐。
用wait()/notify()实现生产消费模型
生产消费模型的设计思路
- 生产者:运行的时候产生数据放入缓冲容器,并且唤醒(notify())消费者,当缓冲区数据存满的时候进入wait()状态.
- 消费者:运行的时候取出并且消费缓冲区的数据,且唤醒(notify())生产者,当缓冲区数据为空的时候进入wait()状态
- 缓冲区:用Queue队列来做缓冲区存取数据,用offer()来存、用poll()来取。因为相比于add()和remove()相比他们取用失败会返回false和null而后者会抛出异常
代码实现
import java.util.LinkedList;
import java.util.Queue;
public class Test1 {
//申请一个容量为10的仓库
private static final int FULL=10;
public static void main(String args[]) {
//创建仓库队列
Queue<Integer> queue=