简介

ReentrantLock是一种可重入锁,可以等同于synchronized的使用,但是比synchronized更加的强大、灵活。
一个可重入的排他锁,它具有与使用 synchronized 方法和语句所访问的隐式监视器锁定相同的一些基本行为和语义,但功能更强大。ReentrantLock 将由最近成功获得锁定,并且还没有释放该锁定的线程所拥有。当锁定没有被另一个线程所拥有时,调用 lock 的线程将成功获取该锁定并返回。如果当前线程已经拥有该锁定,此方法将立即返回。可以使用 isHeldByCurrentThread() 和 getHoldCount() 方法来检查此情况是否发生。

内部实现

ReentrantLock内部拥有一个Sync内部类,该内部类继承自AQS,该内部类有两个子类FairSync和NonfairSync,分别代表了公平锁和非公平锁,ReentrantLock默认使用非公平锁

那么ReentrantLock内部的公平锁和非公平锁有什么区别呢?

区别主要在于两种锁实现的获取锁的方式,tryAcquire方法实现的不同:

首先来看看非公平锁:
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();//获取state
if (c == 0) {//state == 0表示锁没有被任何线程持有
if (compareAndSetState(0, acquires)) {//尝试设置state,如果设置成功,则获取到锁
setExclusiveOwnerThread(current);// 将当前锁的持有者设置为当前线程
return true;
}
}
else if (current == getExclusiveOwnerThread()) {//如果当前线程是锁的持有者,直接返回成功
int nextc = c + acquires;
if (nextc < 0) // overflow
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;//否则,获取锁失败
}
可以看到,非公平锁获取锁的过程是:首先判断当前锁是否被其他线程持有,如果是,直接返回失败,否则尝试获取锁 再来看看公平锁的加锁过程:
protected final boolean tryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
if (!hasQueuedPredecessors() &&
compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < 0)
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
} 对比上面的非公平锁的加锁过程,可以看到公平锁多了一个hasQueuedPredecessors方法的判断,来看看该方法的实现:
public final boolean hasQueuedPredecessors() {
// The correctness of this depends on head being initialized
// before tail and on head.next being accurate if the current
// thread is first in queue.
Node t = tail; // Read fields in reverse initialization order
Node h = head;
Node s;
return h != t &&
((s = h.next) == null || s.thread != Thread.currentThread());
} 其实就是判断当前线程是否为CLH队列的头节点 我们知道,尝试获取锁失败的线程都会被放入到CLH队列中,然后自旋尝试获取锁。对比公平锁和非公平锁的获取方式可以看到,公平锁之所以公平,是因为后续的线程必须进入到CLH同步队列中排队等候获取锁,但是分公平锁不需要,如果某个线程尝试获取锁的时候当前锁刚好被释放掉,那么它可以直接尝试获取锁,如果获取锁成功,直接执行,获取失败时,才进入到CLH同步队列

总结

通过上面的分析可以看到,公平锁是将所有线程依次放入CLH同步队列,然后再从队列中依次取出来执行;而非公平锁是部分已经进入同步队列的线程会像公平锁一样获取锁,但是其他尚且没有进入同步队列的线程可以与CLH同步队列中的首节点线程竞争锁;这也是为什么非公平锁性能比公平锁性能更佳的原因

ReentrantLock中的公平锁与非公平锁的更多相关文章

  1. java多线程20 : ReentrantLock中的方法 ,公平锁和非公平锁

    公平锁与非公平锁 ReentrantLock有一个很大的特点,就是可以指定锁是公平锁还是非公平锁,公平锁表示线程获取锁的顺序是按照线程排队的顺序来分配的,而非公平锁就是一种获取锁的抢占机制,是随机获得 ...

  2. 深入了解ReentrantLock中的公平锁和非公平锁的加锁机制

    ReentrantLock和synchronized一样都是实现线程同步,但是像比synchronized它更加灵活.强大.增加了轮询.超时.中断等高级功能,可以更加精细化的控制线程同步,它是基于AQ ...

  3. Java中的公平锁和非公平锁实现详解

    前言 Java语言中有许多原生线程安全的数据结构,比如ArrayBlockingQueue.CopyOnWriteArrayList.LinkedBlockingQueue,它们线程安全的实现方式并非 ...

  4. 深入分析ReentrantLock公平锁和非公平锁的区别

    在ReentrantLock中包含了公平锁和非公平锁两种锁,通过查看源码可以看到这两种锁都是继承自Sync,而Sync又继承自AbstractQueuedSynchronizer,而AbstractQ ...

  5. Java之ReentrantLock公平锁和非公平锁

    在Java的ReentrantLock构造函数中提供了两种锁:创建公平锁和非公平锁(默认).代码如下: public ReentrantLock() { sync = new NonfairSync( ...

  6. 第五章 ReentrantLock源码解析1--获得非公平锁与公平锁lock()

    最常用的方式: int a = 12; //注意:通常情况下,这个会设置成一个类变量,比如说Segement中的段锁与copyOnWriteArrayList中的全局锁 final Reentrant ...

  7. 深入分析ReentrantLock公平锁和非公平锁的区别 (转)

    在ReentrantLock中包含了公平锁和非公平锁两种锁,通过查看源码可以看到这两种锁都是继承自Sync,而Sync又继承自AbstractQueuedSynchronizer,而AbstractQ ...

  8. 理解ReentrantLock的公平锁和非公平锁

    学习AQS的时候,了解到AQS依赖于内部的FIFO同步队列来完成同步状态的管理,当前线程获取同步状态失败时,同步器会将当前线程以及等待状态等信息构造成一个Node对象并将其加入到同步队列,同时会阻塞当 ...

  9. 死磕 java同步系列之ReentrantLock源码解析(一)——公平锁、非公平锁

    问题 (1)重入锁是什么? (2)ReentrantLock如何实现重入锁? (3)ReentrantLock为什么默认是非公平模式? (4)ReentrantLock除了可重入还有哪些特性? 简介 ...

随机推荐

  1. [BOI2009]Radio Transmission 无线传输

    题目描述 给你一个字符串,它是由某个字符串不断自我连接形成的. 但是这个字符串是不确定的,现在只想知道它的最短长度是多少. 输入输出格式 输入格式: 第一行给出字符串的长度,1 < L ≤ 1, ...

  2. 13、如何拆分含有多种分隔符的字符串 14、如何判断字符串a是否以字符串b开头或结尾 15、如何调整字符串中文本的格式 16、如何将多个小字符串拼接成一个大的字符串

    13.如何拆分含有多种分隔符的字符串 import re s = "23:41:2314\1234#sdf\23;" print(re.split(r'[#:\;]+',s))   ...

  3. 枚举加countdownLatch的使用

    package com.cxy.juc; import java.util.concurrent.CountDownLatch; public class CountDownlatchDemo { p ...

  4. python中 try、except、finally执行顺序

    我们虽然经常用到try...except 作为异常补货,但是其实很少去研究try源码和机制,也许点进去看过,也是看不出个所以然来 class Exception(BaseException): &qu ...

  5. css translate/rotate 空间坐标轴

    参考:https://www.cnblogs.com/zhangnan35/p/10709876.html https://www.cnblogs.com/zyrblog/p/11142624.htm ...

  6. 微信小程序picker下拉绑定数据

    页面部分 <picker mode = "selector" bindchange="bindPickerChange" value="{{pr ...

  7. 前端 css 进阶

    内容目录: 1.css盒子模型 2.浮动 float 3.溢出 overflow 4.定位 position 5. z-index 6.opacity 1.css盒子模型 margin:用来调节盒子与 ...

  8. windows下安装jenkins初级(1)

    这里是基于Windows系统下安装Jenkins 首先下载jenkins 下载地址:https://jenkins.io/download/ 选择所需要的系统 我这里选择Windows 开始安装 一直 ...

  9. mysql开启慢查询报错:

    1.进入mysql命令行:#mysql -uroot -p123456,执行下面的命令开启慢查询报错: set global slow_query_log=on; set global long_qu ...

  10. 区别 |python-pandas库set_index、reset_index用法区别

    1.set_index() 作用:DataFrame可以通过set_index方法,将普通列设置为单索引/复合索引. 格式:DataFrame.set_index(keys, drop=True, a ...