JAVA-初步认识-第十四章-线程间通信-多生产者多消费者问题-JDK1.5新特性解决办法-范例
一.
一个锁挂多组监视器的情况,讲述了java.util.concurrent.locks包里面的lock接口和conditon接口的一些特点。
必须要明确,lock接口和condition接口有什么作用。
有人说连个对象都没有,老是说接口,自己实现么?lock和condition暴露的就是接口,我们就是在使用这个接口,并不实现。会实现吗?不可能嘛。给我们接口,我们就能用,怎么用?它怎么实现,怎么用。它自己在做实现,我直接拿它用就完事儿了。接口有扩展性。
API中不光介绍了概念,还给出了范例,帮助我们学会使用相应的概念。
下面研究一下condition的范例(范例中用的都是变量,而不是生产者和消费者的概念),
BounderBuffer是缓冲区,里面有一个锁,两个监视器,非满,非空。之前定义的是name变量,记录的是烤鸭的名字。这里定义的是一个数组容器,这里面放的是对象,object[],说白了人家是真正定义了能装一百只鸭子的筐。putptr是存,takeptr是取,count是计数,这些全都用来操作数组的变量。
这个buffer里面一共有两个方法,一个是存,一个是取。
这个存呢?就是你给我一只鸭子(object x),进来后就拿到锁了lock.lock();如果你拿到锁了,在里面的操作过程中,这哥们能取吗?拿不到,这锁是互斥的。你拿到,我就拿不到。现在,我们拿到锁了,就进来开始判断了,是while判断。判断标记的时候,一定要用while。为什么要用while,因为安全。每一次醒来,都先判断标记,这是最安全的做法,因为标记是否改动,谁都不知道。因此,每次醒过来,我都看一看,到底有没有,有我就不做,没有我就做。signal是不是All就不一定了,如果能实现唤醒对方,我根本不需要All,因为All会把本方唤醒。如果挂了多组监视器,就可以唤醒对方。把对方全唤醒,和唤醒一个还是有点区别的。把对方全唤醒,全都活了,但是只有一个在运行,运行完之后改标记,这时另外一个线程过来,判断标记还是挂了,这个线程根本就不需要过来。那怎么办呢?唤醒一个就完事儿了,这是效率问题。count==items.length,计数器判断的是数组的长度,如果相等,那么就烤到位了,不用烤了直接await。没烤满呢?来一只,存一只,items[putptr]=x。putptr是指针。