synchronized和ReentrantLock的区别
synchronized和ReentrantLock的区别
| 区别 | synchronized | ReentrantLock |
|---|---|---|
| 底层实现 | JVM内置的C++实现 | Java代码,基于AQS框架实现 |
| 底层机制 | Monitor | 基于AQS框架实现 |
| JVM实现 | 偏向锁、轻量级锁、重量级锁 | 无 |
| 可重入 | 是 | 是 |
| 可中断 | 否 | lockInterruptibly() |
| 非阻塞获取 | 否 | tryLock() |
| 公平性 | 非公平 | 可配置公平/非公平 |
| 锁释放 | 自动释放 | 手动释放 |
| 超时获取锁 | 不支持 | tryLock(timeout) |
| 条件变量 | 不支持 | 多个condition |
| 锁状态检查 | 是 | isLocked() |
底层原理
synchronized的底层原理
字节码层面,synchronized会编译成monitorenter和monitorexit指令。
monitorenter指令会尝试获取锁,如果锁被其他线程持有,则当前线程会阻塞等待,直到锁被释放。
monitorexit指令会释放锁,允许其他线程获取锁。(monitorexit有两个,一个是正常退出,一个是异常退出)
每个对象都关联一个monitor,monitor记录了持有锁的线程、重入次数、等待队列等信息。
ReentrantLock的底层原理
Lock底层是基于AQS实现的,lock方法调用sync。sync的acquire方法,tryAcquire方法尝试获取锁,release方法释放锁。
- state:同步状态(0表示未锁定,大于0表示锁定次数)
- CLH队列:等待线程的双向队列
- CAS:无锁的原子操作
使用方式
- synchronized可以修饰方法、代码块,自动释放锁
- 要先newReentrantLock(),并且ReentrantLock需要手动调用lock()和unlock()方法,需要在finally块中释放锁。(必须手动释放 不然会造成死锁)
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 花海!
