synchronized 和 ReentrantLock

227 阅读2分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第21天,点击查看活动详情

synchronized 和 ReentrantLock 有什么区别?

synchronized: synchronized 属于独占式的悲观锁,是通过 JVM 实现,synchronized 在同一时刻只允许一个线程操作资源。

ReentrantLock: ReentrantLock 是 Lock 的默认实现方式之一,它是基于 AQS 实现的,默认是非公平,内部有一个 state 的状态字段用于表示锁是否被占用,如果是 0 则表示锁未被占用,当线程把 state 改为 1,则表示线程成功获得了锁,其他线程则需要排队等待获取锁。

  1. synchronized 和 ReentrantLock 都提供了锁的功能

  2. ReentrantLock 可设置为公平锁,而 synchronized 不能

  3. ReentrantLock 只能修饰代码块,而 synchronized 可以用于修饰方法、修饰代码块等;

  4. ReentrantLock 需要手动加锁和释放锁,锁没有释放,则会造成资源被占用一直得不到释放,而 synchronized 无需手动释放锁,由jvm内部自动加锁和释放锁

  5. ReentrantLock 可以主动的获取是否成功获得了锁的信息,而 synchronized 不行,可以理解为黑盒方法

使用

ReentrantLock的使用: ReentrantLock 是通过 lock() 来获取锁,通过 unlock() 释放锁,使用代码:

Lock lock = new ReentrantLock();
try {
    lock.lock();
} finally {
    lock.unlock();
}

synchronized的使用:

  1. 直接修饰在方法声明上
  2. 声明在方法块中

原理的区别

Synchronized由monitorenter实现:

  1. 每个对象有一个锁monitor,当monitor被占用时就会处于锁定状态

  2. 如果monitor的进入数为0,则该线程进入monitor,然后将进入数设置为1,该线程即为monitor的所有者

  3. 如果monitor的进入数不为0,则表示已有线程进入monitor,则该线程进入阻塞状态

  4. 线程执行完成后,退出monitor,将进入数设置为0

ReenTrantLock由CAS+CLH队列来实现:

  1. CAS:Compare and Swap,比较并交换,此操作为一个原子操作
  2. CLH队列:带头结点的双向非循环链表