目录
ReentrantLock
ReentrantLock 是一个可重入的互斥锁,又被称为“独占锁”。ReentrantLock 类实现了 Lock ,它拥有与 synchronized 相同的并发性和内存语义,但是添加了类似锁投票、定时锁等候和可中断锁等候的一些特性。此外,它还提供了在激烈争用情况下更佳的性能。
ReentrantLock 锁在同一个时间点只能被一个线程锁持有;而可重入的意思是,ReentrantLock 锁,可以被单个线程多次获取。
ReentrantLock 分为“公平锁”和“非公平锁”,它们的区别体现在获取锁的机制上是否公平。“锁”是为了保护竞争资源,防止多个线程同时操作线程而出错,ReentrantLock 在同一个时间点只能被一个线程获取,当某线程获取到“锁”时,其它线程就必须等待。
ReentraantLock 是通过一个 FIFO 的等待队列来管理获取该锁所有线程的:
-
在“公平锁”的机制下,线程依次排队获取锁;
-
而“非公平锁”在锁是可获取状态时,不管自己是不是在队列的开头都会获取锁。
公平锁和非公平锁
-
公平锁 : 锁被释放之后,先申请的线程先得到锁。性能较差一些,因为公平锁为了保证时间上的绝对顺序,上下文切换更频繁。
-
非公平锁:锁被释放之后,后申请的线程可能会先获取到锁,是随机或者按照其他优先级排序的。性能更好,但可能会导致某些线程永远无法获取到锁。
synchronized 和 ReentrantLock 有什么区别?
- 两者都是可重入锁。
可重入锁 也叫递归锁,指的是线程可以再次获取自己的内部锁。比如一个线程获得了某个对象的锁,此时这个对象锁还没有释放,当其再次想要获取这个对象的锁的时候还是可以获取的,如果是不可重入锁的话,就会造成死锁。
JDK 提供的所有现成的 Lock 实现类,包括 synchronized 关键字锁都是可重入的。
-
锁的实现
-
synchronized 是依赖于 JVM 实现的。
-
ReentrantLock 是 JDK 层面实现的。
也就是 API 层面,需要 lock() 和 unlock() 方法配合 try/finally 语句块来完成。
-
相比 synchronized,ReentrantLock 增加了一些高级功能。主要来说主要有三点:
-
等待可中断 : ReentrantLock 提供了一种能够中断等待锁的线程的机制,通过 lock.lockInterruptibly() 来实现这个机制。也就是说正在等待的线程可以选择放弃等待,改为处理其他事情。
-
可实现公平锁 : ReentrantLock 可以指定是公平锁还是非公平锁;而 synchronized 只能是非公平锁。
所谓的公平锁就是先等待的线程先获得锁。ReentrantLock 默认情况是非公平的,可以通过 ReentrantLock 类的 ReentrantLock(boolean fair) 构造方法来指定是否是公平的。
-
可实现选择性通知(锁可以绑定多个条件):
-
synchronized 关键字与 wait() 和 notify()/notifyAll() 方法相结合可以实现等待/通知机制。
-
ReentrantLock 类也可以实现等待/通知机制,但是需要借助于 Condition 接口与 newCondition() 方法。
-