Java/synchronized 和 ReentrantLock
在 Java5 之前,只有synchronized
一种锁,在 Java5 之后,增加了ReentrantLock
。ReentrantLock
位于 java.util.concurrent.locks 包,和 CountDownLatch、FutureTask、Semaphore 一样基于 AQS 实现,能够实现比synchronized
更细粒度的控制,如控制公平性(fairness)。使用ReentrantLock
需要注意的是在调用 lock() 方法之后,必须调用 unlock() 释放锁。在 Java6 后经过优化的synchronized
性能未必比ReentrantLock
低,并且synchronized
也是可重入的。
公平锁和非公平锁
- 公平锁:获取锁的顺序按照调用 lock() 方法的顺序,
ReentrantLock
可以实现公平锁 - 非公平锁:抢占的顺序不一定,
synchronized
时非公平锁 #ReentrantLock
公平性的设置在实际场景中,公平性不一定是最重要的,Java 默认的线程调度策略很少会导致饥饿情况的发生,如果要保证公平性,则会引入额外的开销,会导致吞吐量有一定程度的下降,所以只有当实际业务必须实现公平锁的时候,才有必要去使用公平锁。1
2//参数为 true 时,倾向于将锁赋予等待时间最久的线程
ReentrantLock lock=new ReentrantLock(true);
ReentrantLock
可以将锁对象化
- 可以判断是否由线程,或者某个特定线程在排队等待获取锁
- 在获取锁时可以设置超时参数,在一定时间内获取不到锁则放弃
- 可以感知是否成功获取到锁
总结
synchronized
是关键字,ReentrantLock
是类ReentrantLock
可以对获取锁的等待时间进行设置,避免死锁ReentrantLock
可以获取各种锁的信息ReentrantLock
可以灵活地实现多路通知- 二者的锁机制是不一样的:
synchronized
操作的是对象头中的 Mark Word,ReentrantLock
是通过调用 Unsafe 类的 park() 方法来获取锁