JAVA-初步认识-第十四章-线程间通信-多生产者多消费者问题-JDK1.5新特性-Lock
一.
前面的过程中,while和notifyAll的加入,解决了多生产多消费程序中的问题,但是notifyAll固有的属性带了程序的降低。后期JDK升级的过程中,提供新的工具来解决效率降低的问题。
在JDK1.5版本中,将版本号改为了5.0,后面都是6.0,7.0和8.0....JDK5.0版本中提供了什么东西来解决这样的问题,或者是不是给我们提供了相关的替代品。这里面找寻一个软件包,(类要存放在不同的软件包中)。这个包就是java.util.concurrent.locks。
对于其中的Lock接口,进行讲解。(截图中的方法和语句是指同步函数,和同步代码块。语句指代码块有点奇怪?)
Lock接口的出现是对synchronized的替代,为什么要替代?原因是:以前使用synchronized时,要么是同步函数,要么是同步代码块。它仅仅是一个封装体,自带一个锁。后期升级,把它(锁)变成了一个对象。为什么?因为锁变成对象,就具备了一些最基本动作,获取锁,释放锁。直接把锁这个事物封装成了对象。(封装思想用的很多,很深入)
现在举例来看一下,封装成对象的锁
(在这里同步代码块放置在show的函数中,或者说show代码块中。我们对于代码块的认识或者封装的认识不够,代码块可以放置于)
有没有注意过锁是什么时候拿到的?什么时候消失的?
同步代码块中,对于锁的操作是隐式的。(视频中口语式的解释是,线程拿着锁进入对应的同步代码块中,执行相应的code代码,结束后释放锁,给下一个线程使用)而后期把锁封装成了对象,按照面向对象的方式来思考锁的动作,获取锁和释放锁应该是锁自己最清楚。把隐式的动作变为显示的动作。
现在讨论的都不是新技术,而是说1.5版本以后,对以前的知识是如何进行替换的。替换的好处先不介绍,先说一下替换的样子。
现在同步变成了一个对象,叫做Lock。而这Lock被封装成两个对象后,它提供了两个方法,获取锁和释放锁。它把这两个动作变成了功能,以前获取和释放是底层自动帮我们完成的,而现在变成了两个功能,什么时候获取,什么时候释放,是由我们自己说了算。
在新版本中上图的代码就发生了变化,
原先的写法中,锁是提前定义好的object类,或者本类this。新的写法中lock定义在哪儿?而且在API中,lock是个接口,接口应该有实现,应该有子类。
继续阅读API,关于Lock接口重要的部分如上面的截图所示。有一个ReentrantLock子类实现了Lcok接口,它也存在属于自己的构造函数。
下图展现的就是自定义锁,和它在函数中的具体使用。自己控制锁的获取,锁的释放。
之前,我们是通过同步代码块和对象相结合的方式,完成了线程的同步。现在是通过一个锁对象,获取和释放锁方法,完成了完成了这部分代码(code....)的同步。这两种代码是一样的,只是换了不同的表现形式。
互斥锁,互斥就是排斥,你在我不能在。
如果出现这样的情况怎么办?如果在我的获取锁以后,我在操作代码的时候,这代码发生了异常。发生异常就要实现跳转,释放锁这句话就读不到。释放锁的动作没拿到,那么这个哥们还拿着锁呢,别人也就无法进来。这就要求我们无论是否发生异常,一定要释放锁,不然其他线程就起不了作用了。
因此,Lock.unlock();这句话就要放置在finally当中。至于异常你捕不捕捉,这个锁一定要释放。正确的写法如下,
到此,我们已经将Lock接口演示完了。
现在修改以前的代码,使其符合现在的规则,
(定义的Lock接口是外来的包中的,必须要写全它的名称。locks是什么意思,哪来的?)
为了不那么麻烦地书写对象的前缀名称,先定义好包。