ReentrantLock 用法详解
2018-08-06 15:48:31 最后更新: 2018-08-06 15:51:18 访问数量:2200
2018-08-06 15:48:31 最后更新: 2018-08-06 15:51:18 访问数量:2200
此前的日志中我们介绍了 synchronized 锁的使用及实现原理:
文中,我们看到,jdk1.6 对 synchronized 锁进行了一系列的优化,使得我们再也不用为 synchronized 锁的性能担忧,在此之前,synchronized 锁因为其性能问题是很少被使用的,那时,最常用的锁结构就是今天我们要介绍的 ReentrantLock 锁
虽然时至今日,优化后的 synchronized 锁的性能已经与 ReentrantLock 接近,但 ReentrantLock 仍然具备着 synchronized 所不具备的很多优势:
因此,在高度竞争的并发环境下,以及较为复杂的使用场景中,ReentrantLock 都是 synchronized 的有力替代品
本篇日志中,我们就来介绍一下 ReentrantLock 的用法,下一篇日志中,我们详细的剖开源码解析 ReentrantLock 的实现原理
ReentrantLock 类提供了最基本的加锁和解锁方法:
我们通过最基本的加锁方法实现上一篇日志中提到的自增方法锁
这个方法保证了线程安全,他和 synchronized 关键字实现了相同的效果:
显然,synchronized 关键字的实现更为简洁和清晰,同时,如果 ReentrantLock 忘记调用 unlock 方法将会造成死锁,这是必须要注意的一点
因此,如果仅仅是想要进行上面代码中这样的加锁和解锁,synchronized 还是最好的选择
使用 synchronized 锁是不保证等待的线程获取到锁的顺序的,这就是非公平锁,除了默认的非公平锁构造方法外,ReentrantLock 还提供了一个带有 boolean 参数的构造方法:
如果传入参数为 true,则会创建公平锁,所谓的公平锁,就是保证了先进入等待的线程一定先获取到锁
可以通过 isFair 方法查询 ReentrantLock 对象是否是公平锁:
ReentrantLock 提供了 tryLock 方法与 lockInterruptibly 方法用来实现非阻塞式锁、时间限制锁与可中断锁
以上三种锁方式,synchronized 都是无法实现的,正如我们上一篇日志中所提到,interrupt 方法是不会中止正在等待获取 synchronized 锁的线程的
Object 类提供了只能在 synchronized 代码块中使用的 wait、notify、notifyAll,ReentrantLock 也拥有类似但更为强大的等待和唤醒机制,这就是通过 Condition 对象唤醒的
通过 newCondition 方法,可以创建出 Condition 对象
Condition 接口提供了如下的方法:
上面的五个等待方法中,除了 awaitUninterruptibly 方法,其他四个都可以被 interrupt 方法中断,而 signal 和 signalAll 方法可以中断上述所有等待方法
但是,signal 和 signalAll 方法只能唤醒通过当前 Condition 对象调用过等待方法的线程
基于上述特性,我们可以精准的控制让某个指定的线程被唤醒,而 Object 的 notify、notifyAll 方法的唤醒则是随机的,同一个 ReentrantLock 每次调用 newCondition 方法都将获得不同的 Condition 对象
除了上述强大的加锁与等待、唤醒接口外,ReentrantLock 还提供了丰富而强大的查询接口,让你了解到锁相关的各种情况:
欢迎关注微信公众号,以技术为主,涉及历史、人文等多领域的学习与感悟,每周三到七篇推文,只有全部原创,只有干货没有鸡汤