0%

synchronized与ReentrantLock

.image-20220420121146774

ReentrantLock

  • ReentrantLock是一个可重入的互斥锁,又被称为“独占锁”
  • ReentrantLock在同一个时间点只能被一个线程锁持有,“可重入”意为ReentrantLock锁可以被同一个线程多次获取
  • 公平锁与非公平锁
    • 公平锁:就是谁等待时间最长,谁就先获取锁,ReentrantLock中用AQS队列实现
    • 非公平锁:随机获取,CPU时间片轮询到哪个线程,哪个线程就能获取锁

使用语法

1
2
3
4
5
6
Lock lock=new ReentrantLock();
try{
lock.lock();
}finally{
lock.unlock();
}

构造方法

1
2
3
4
5
6
7
//默认创建非公平锁
public ReentrantLock() {
sync = new NonfairSync();
}
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}

NonfairSync & FairSync都是基于AQS队列(AbstractQueuedSynchronizer)来管理获取该锁的所有线程
它是基于FIFO实现的等待队列,AQS队列基于双向链表,如果一个线程获取锁就直接成功,如果失败了就将其放入等待队列当中

获取锁

1
2
3
4
5
public void lock() {
sync.lock();
}
//sync是Sync抽象类的Instance
//Sync抽象类被FairSync和NonFairSync继承
  1. CAS操作抢占锁,抢占成功则将持有数的设为1,将线程信息记录到锁当中
  2. 如果当前线程已经获取了锁,将持有数+1
  3. 抢占不成功,新建一个Node插入到当前AQS队列的尾部

释放锁

  1. 若当前线程是锁的持有者(与锁中的信息进行比较),将持有数-1。当状态值减为0时,释放锁
  2. 若当前线程不是锁的持有者抛出IllegalMonitorStateException

synchronized

JDK1.6后对synchronized进行了优化,不再是重量级锁

主要存在四种状态,依次是:无锁状态、偏向锁状态、轻量级锁状态、重量级锁状态。但是锁的升级是单向的,也就是说只能从低到高升级,不会出现锁的降级