生产者消费者模型,是每一个学习多线程的的人都需要知道的模型;
大致情况就是:有两个线程,一个负责生产产品,一个消费产品,两者公用同一块内存区域,也就是产品放在了同一块内存上面,如果两个线程没有采用一定的措施或者采用的策略错误的情况下,容易出现一系列的问题,例如数据一致性问题,死锁问题;
2为什么需要生产者消费者模型在多线程世界里,生产者就是生产数据的线程,消费者就是消费数据的线程;如果生产者处理速度很快,而消费者处理速度很慢,那么生产者就必须等待消费者处理完,才能继续生产数据;同样的道理,如果消费者的处理能力大于生产者,那么消费者就必须等待生产者;为了解决这个问题于是引入了生产者和消费者模式。3生产者-消费者模型(线程阻塞,线程唤醒)举例:线程1去奶茶,没有奶茶了,它就不执行了;线程二生产奶茶,通知线程1继续执行;
下面这个例子不大好,使用了Java线程已经抛弃的方法
打印结果如下,最开始没奶茶,后来有了奶茶通知了挂起的线程,那个线程就得以继续执行
上面这个就是经典的生产者-消费者模型,但是为啥这个例子当中的线程方法被弃用了呢?往下看一个例子
suspend和resume加锁导致死锁
打印结果
这个线程不用等了,一直都是在这里挂起了,竞争不到锁,没办法通知挂起的线程继续执行;
如果suspend比resume慢执行,也会导致线程永久挂起
打印结果,通知完了,那边才开始挂起
那么Java现在推荐哪一种方式进行使用呢~
wait/notify机制
这个机制要求这两个方法只能由同一对象锁的持有者线程进行调用,也就是卸载同步代码块里面,否则会抛出
IllegalMonitorStateException异常;
wait方法导致当前的线程进入等待状态,加入该对象的等待集合中,并发放弃当前持有的对象锁;
notify/notifyAll方法唤醒一个或所有正在等待这个对象锁的线程;
注意:虽然会wait自动解锁,但是对顺序有要求,如果在notify被调用之后才开始wait方法的调用,线程会永远处于WAITING状态
先来一个正常的演示(打印跟前面正常的一致)
可以看到,如果是suspend/resume的话,这个程序是会导致死锁的,可是这里采用的是wait/notify机制,会自动释放锁
如果notify比waiting先执行,
那么会导致线程一直处于WAITING的状态
说个题外话,我觉得这个就跟你的女神已经通知你,我们不可能在一起了,然后你还一直在等待
还有另外一个机制
park/unpark机制
park表示等待一个“许可”
unpark表示授予一个"许可"
park/unpark机制有一个好处就是如果提前颁发“许可”了
也不会导致线程一直处于挂起或者是死锁的转态
但是它不会主动去释放锁
park比unpark提前执行的例子
本样式由135编辑器出品,不允许任何第三方编辑器抄袭使用,违者加锁导致死锁的例子
【总结】
suspend/resume机制
resume先执行,suspend慢执行;resume/suspend加锁;都会导致死锁
wait/notify机制
wait/notify加锁了会自动释放锁,但是notify比wait先执行依然会线程永久挂起
park/unpark机制
park/unpark不会自动释放锁,但是先后执行顺序不会导致线程永久挂起
【提醒】
代码当中使用if语句来判断是否进入等待状态,
是错误的
官方建议是采用while情况下,判断是否可以将线程挂起