Water2Wine

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

Lock与synchronized提供了相同的互斥性和内存可见性,以及可重入的加锁语义。

但除此之外,Lock提供了一种无条件的、可轮询的、可定时的、可中断的以及可分离读写互斥性的锁获取操作。

功能差异

1. 可轮询、可定时的锁获取操作 -- tryLock()

这也是我在之前的博客中所提到的,应对锁顺序死锁问题的一种解决方案。通过tryLock()来获取两个锁,如果不能同时获得,那么就会回退并重新尝试。在休眠时间中包括固定部分和随机部分,从而降低发生活锁的可能性。

2. 可中断的锁获取操作 -- lockInterruptibly() throws InterruptedException

正如定时的锁获取操作能在带有时间限制的操作中使用独占锁,可中断的锁获取操作同样能在可取消的操作中使用加锁。

synchronized内置锁是不能响应中断机制的,这些不可中断的阻塞机制将使得可取消的任务变得复杂。

lockInterruptibly方法能够在获得锁的同时保持对中断的响应,并且由于它包含在Lock中,因此无需创建其他类型的不可中断阻塞机制。

3. 非块结构的加锁

在synchronized内置锁中,锁的获取和释放等操作都是基于代码块的——释放锁的操作总是与获取锁的操作处于同一个代码块。

而lock则可以实现释放锁与获取锁的分离。这在例如链表加锁的场景中会很有用,我们只会在获得了下一个结点的锁的情况下才会释放该结点上的锁。

4. 可分离读写互斥性的所获取操作 -- ReadWriteLock()

在读写操作的加锁机制中,虽然可以避免“写/写”冲突和“写/读”冲突,但是同样也让“读/读”这个具备线程安全性的操作成为了不可能。

在这种情况下就可以使用读/写锁:一个资源可以被多个读操作访问,或者被一个写操作访问,但两者不能同时进行。

Lock与synchronized差异点总结

  1. Lock是一个接口,而synchronized是Java中的关键字,synchronized是内置的语言实现,synchronized是在JVM层面上实现的,不但可以通过一些监控工具监控synchronized的锁定,而且在代码执行时出现异常,JVM会自动释放锁定。
    但是使用Lock则不行,lock是通过代码实现的,要保证锁定一定会被释放,就必须将 unLock()放到finally{} 中;

  2. synchronized在发生异常时,会自动释放线程占有的锁,因此不会导致死锁现象发生;
    而Lock在发生异常时,如果没有主动通过unLock()去释放锁,则很可能造成死锁现象,因此使用Lock时需要在finally块中释放锁;

  3. Lock可以让等待锁的线程响应中断,线程可以中断去干别的事务,而synchronized却不行,使用synchronized时,等待的线程会一直等待下去,不能够响应中断

  4. Lock可以通过tryLock知道有没有成功获取锁(会将失败记录到日志),而synchronized却无法办到。

  5. Lock可以提高多个线程进行读操作的效率(ReadWriteLock)


注意:Lock()与ReadWriteLock()是两个不同的接口,实现类分别是ReentrantLock()和ReentrantReadWriteLock()

posted on 2020-03-10 21:28  Water2Wine  阅读(163)  评论(0编辑  收藏  举报