java并发编程(显式锁)

版权声明:转载标明来源! https://blog.csdn.net/qq_39213969/article/details/88925347

一,java5.0之前,调节共享对象的方式只有synchronized(内部锁机制)还有volatile(变量)。之后,引用了ReentranLock锁,他与之前的机制相反,ReentranLock并不是作为内部锁的替代,而是一种全新的锁形式。当内部锁被证明受到局限性时。。采用 ReenrantLock锁 进行可选选择的高级特性实现锁的功能(解决共享对象的访问问题)。

二. Lock(接口) 和 ReentrantLock锁(实现Lock接口的类)

1.Lock接口,定义了一些抽象的锁操作。与内部加锁机制不行,Lock提供了无条件的,可轮询的,定时的,可中断的锁获取操作,所有加锁以及解锁的操作都是显式的。
注意:Lock的实现必须提供与内部加锁相同的内存可见性的语义。但是加锁的语义,调度算法,顺序保证,性能特性这些可以不同。
(获取ReentrantLock与进入synchronized快有相同的语义,释放与退出语义也相同)

2.R锁实现了Lock接口的所有获取锁的模式,R锁为处理不可用的锁提供了更多的灵活性。

3.为什么建立R锁? 建立R锁不是为了替代内部锁,而只是为了完善内部锁
(1)不能中断那些正在等待获取锁的线程。
(2)一旦线程陷入死锁(或者请求要求失败陷入阻塞),线程会无限期的等待下去。
(3)内部锁必须在获取他们的代码块中释放,这很好的简化了代码,与异常处理机制能够很好的互动。但是在某些情况下一个灵活的枷锁机制能够提升活跃度以及性能。
(4)内部锁必须在获取她的代码块中释放,而R锁只能在finally中释放。注意:若果R锁守护的大代码在try之前就已经抛出了异常那么他将永远不会被释放了。
(5)如果对象能够被置于不一致的状态,那么可能需要额外的try-catch以及try-finally 快(任何情况下,无论加什么锁 都要特别关注住异常异常)
(7)忘记使用finally快释放锁是一个定时炸弹。一旦发生异常他很难知道放生错误的地点以及时间,因为根本没有记录锁本应该被释放的位置以及时间,所以他更加的危险,因为当程序的控制权不属于守护的代码块时,释放锁不会自动清除锁,如果忘记finally手动清除锁,那么将引发定时炸弹。

3.可轮询以及可定是的请求:(1)一定时间内没有获得所有需要的锁(比如需要两个锁),返回失败状态。(再重新尝试)释放锁一定时间内再次重新拿到控制权。(2)实现具有时间限制的活动也有用(线程陷入阻塞。定时锁设置相应的超时机制,如果活动在期待的时间内没能获得结果,这个机制能够使程序提前返回。)而是用内部锁一旦发起请求,锁就不能停止了,就会陷入阻塞以及死锁。
3.可中断的所获取操作:定时锁能够在限时时间内使用独占锁,可中断的锁获取操作允许在可以取消的活动中使用
内部锁是请求不响应也不会中断的,这些不响应中断的机制,使得可取消任务目的更加的复杂。而在R锁中,当线程正在响应中断操作的时候lockInterruptibly方法使你能够获得锁,并且由于他是内置于Lock,,你不必自己再创建其他不可中断的阻塞机制。

4,一个可中断的锁获取操作的规范形式,要比普通锁复杂一些,因为需要两个try快。定时的tryLock同样响应中断,因此当你需要获取(定时和可中断的锁)时可以使用tryLock这个方法。

三,synchronized(内部锁)和 ReentrantLock锁 之间(二者比较更有优劣)

1.。 ReentrantLock锁(非块结构特性:不能依赖特定的栈结构)是绝对危险的同步工具,(内部锁这个标识相对于显式锁更让人熟悉,亚更加的简洁,目前好多程序已经再用,若果两个锁混用的话,更加容易发生错误)若果忘记在finally快中释放锁(调用unlock)那么就会使得锁永远无法被释放,你的代码也许可能还能运行,但是无疑是一个定时炸弹,还有可能影响其他的代码。

2,使用reentrantlock锁的原则是:在内部锁不能满足需求时才使用R锁。(也就是满足一下对高级特性的需求)

(1)可定时的,可轮询的,可中断处理的锁获取操作。
(2)公平队列或者是非块结构的锁。否则还是安心使用内部锁吧,亲。

3.疯狂吹内部锁,他相比R锁还有另外一个优点:线程转储能够显示哪些框架调用了哪些锁,并能够识别发生了死锁的那些进程。而JVM并不知哪个线程持有了R锁,因此在调式使用R锁的线程间存在的问题时,无法从中获取帮助。
注意:在jdk6给出了解决方法: 提供了一个管理和调试的接口,锁可以从这个接口进行注册,并通过其他管理和调试接口,从线程转储中得到R的加锁信息。

4.未来发展:未来更倾向于内部锁而不是R锁(显式锁)原因:

(1)内置锁是内置于JVM中的,她能够进行优化
(2)对线程限制的锁对象的锁省略,减小锁的粒度来减小内部锁的同步性(也就是粗化锁)。

四,读-写锁

1。R锁实现了标准的互斥锁,一次只有一个线程能获得相同的R锁。
2,R锁限制了并发性;因此有必要使用读写锁:(一个资源能够被多个读者访问,或者被一个写者访问,两者不能同时进行(放置读取数据过程中存在修改更新数据,导致获取过期的数据))
3.ReadWriteLock锁,两个Lock对象,一个用来读,一个用来写。
注意:读取ReadWriteLock锁守护的数据,必须先获得读取的锁,,,当需要修该读写锁守护的数据时,你必须获得写入的锁。
(1)允许存在多个同时存在的读者,但是只允许存在一个写者。
(2)ReentrantReadWriteLock为两个锁提供了可重进入的加锁定义。
(3)在公平锁中,选择权交给等待时间最长的线程。
(4)如果锁有读者获取,而一个线程请求写入锁,那么不在允许读者获取锁,直到写入锁被受理完毕,并且已经释放了写入锁。
(5)在非公平的锁中,线程允许访问的顺序是不定的。由写者降级为读者是允许的,但是=由读者升级为写者是不允许的(尝试可能会导致死锁)。
(6)ReentrantReadWriteLock的写入锁只有唯一一个所有者,并只能被获取了该所的的线程释放(finally块释放)。

猜你喜欢

转载自blog.csdn.net/qq_39213969/article/details/88925347