一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第21天,点击查看活动详情。
synchronized 和 ReentrantLock 有什么区别?
synchronized: synchronized 属于独占式的悲观锁,是通过 JVM 实现,synchronized 在同一时刻只允许一个线程操作资源。
ReentrantLock: ReentrantLock 是 Lock 的默认实现方式之一,它是基于 AQS 实现的,默认是非公平,内部有一个 state 的状态字段用于表示锁是否被占用,如果是 0 则表示锁未被占用,当线程把 state 改为 1,则表示线程成功获得了锁,其他线程则需要排队等待获取锁。
-
synchronized 和 ReentrantLock 都提供了锁的功能
-
ReentrantLock 可设置为公平锁,而 synchronized 不能
-
ReentrantLock 只能修饰代码块,而 synchronized 可以用于修饰方法、修饰代码块等;
-
ReentrantLock 需要手动加锁和释放锁,锁没有释放,则会造成资源被占用一直得不到释放,而 synchronized 无需手动释放锁,由jvm内部自动加锁和释放锁
-
ReentrantLock 可以主动的获取是否成功获得了锁的信息,而 synchronized 不行,可以理解为黑盒方法
使用
ReentrantLock的使用: ReentrantLock 是通过 lock() 来获取锁,通过 unlock() 释放锁,使用代码:
Lock lock = new ReentrantLock();
try {
lock.lock();
} finally {
lock.unlock();
}
synchronized的使用:
- 直接修饰在方法声明上
- 声明在方法块中
原理的区别
Synchronized由monitorenter实现:
-
每个对象有一个锁monitor,当monitor被占用时就会处于锁定状态
-
如果monitor的进入数为0,则该线程进入monitor,然后将进入数设置为1,该线程即为monitor的所有者
-
如果monitor的进入数不为0,则表示已有线程进入monitor,则该线程进入阻塞状态
-
线程执行完成后,退出monitor,将进入数设置为0
ReenTrantLock由CAS+CLH队列来实现:
- CAS:Compare and Swap,比较并交换,此操作为一个原子操作
- CLH队列:带头结点的双向非循环链表