ReentrantLock类注释

1、可重入互斥锁,意思是表示该锁能够支持一个线程对资源的重复加锁,该锁还支持获取锁的公平和非公平性选择。synchronized关键字隐式的支持重进入。
2、可以通过isHeldByCurrentThread判断当前线程是否拿到锁。
3、构造器接收fairness参数,fairness=true表示公平锁反之是非公平锁。
4、tryLock() 无参方法没有遵循公平性,是非公平的。
5、公平锁的吞吐量没有非公平锁高,需要不断的进行线程之间的切换

ReentrantLock类结构

public class ReentrantLock implements Lock, java.io.Serializable


Lock所定义的方法。

  • lock():获取锁,调用该方法的线程会获取锁。
  • unlock(): 释放锁
  • tryLock(): 尝试非阻塞的获取锁,获取成功返回true,失败返回false。
  • tryLock(long,TimeUtil): 超时获取锁,有三种情况:当前线程在超时时间内获得了锁,当前线程在超时时间内被中断,超时时间结束,返回false。
  • lockInterruptedException(): 可中断的获取锁,所在获取过程中可以中断当前线程。

公平锁与非公平锁

简言之,如果在绝对的时间上,先对锁发起请求的那个线程会先获取锁,遵循FIFO原则,也就是等待时间最长的那个线程最先获取锁。

公平锁和非公平锁只是相对于获取锁的时候而言。

如果一个锁是公平的,那么锁获取的顺序符合时间顺序。当一个线程获取了同步状态就可以认为获取到了锁,刚释放锁的线程下次再获取锁的概率非常大,使其他线程在同步队列中等待,因此非公平锁的线程切换次数很少,这是相对公平锁而言,所以吞吐量上,非公平锁更有优势,所以默认情况下,ReentrantLock的构造就是非公平锁。

互斥锁

互斥锁:同一时刻下,只有一个线程可以拿到锁,其他线程只能在同步队列中等待,只有拿到锁的线程释放锁,其他线程才能去争抢;

构造方法


public ReentrantLock() {
// 默认是非公平锁
sync = new NonfairSync();
} public ReentrantLock(boolean fair) { sync = fair ? new FairSync() : new NonfairSync();
}

从构造器中可以看出,公平锁是依靠 FairSync 实现的,非公平锁是依靠 NonfairSync 实现的。

Sync同步器

Sync继承了AQS,lock方法留给FairSync和NonFairSync两个子类实现,他实现了AQS的tryRelease方法和isHeldExclusively方法。

abstract static class Sync extends AbstractQueuedSynchronizer{
// 尝试释放锁
protected final boolean tryRelease(int releases) {
// releases一般是1,当前线程的同步状态-同步值
int c = getState() - releases;
// 当前线程没有持有锁,抛异常
if (Thread.currentThread() != getExclusiveOwnerThread())
throw new IllegalMonitorStateException();
boolean free = false;
// 当前线程持有的锁都释放了
if (c == 0) {
free = true;
setExclusiveOwnerThread(null);
}
// c!=0代表是重入锁,锁没有释放完毕,前面已经用state-releases
setState(c);
return free; // return false,尝试释放锁失败
} protected final boolean isHeldExclusively() {
// While we must in general read state before owner,
// we don't need to do so to check if current thread is owner
return getExclusiveOwnerThread() == Thread.currentThread();
}
}

加锁

先来看FairSync公平锁的lock方法和tryAcquire

  static final class FairSync extends Sync {
private static final long serialVersionUID = -3000897897090466540L;
// 尝试加锁,acquire方法是AQS的获取锁的方法,如果尝试获取锁失败,会进入同步队列中等待
final void lock() {
acquire(1);
}
/**
AQS的acquire
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
**/ /**
* Fair version of tryAcquire. Don't grant access unless
* recursive call or no waiters or is first.
*/
protected final boolean tryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
// hasQueuedPredecessors 是实现公平的关键
// 会判断当前线程是不是属于同步队列的头节点的下一个节点(头节点是释放锁的节点)
// 如果是(返回false),符合先进先出的原则,可以获得锁
// 如果不是(返回true),则继续等待
if (!hasQueuedPredecessors() &&
compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
// 如果获取锁的线程再次请求锁,将通天阁不状态值增加并返回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;
}
}

再来看NonFairSync非公平锁的加锁和尝试获取锁

 static final class NonfairSync extends Sync {
private static final long serialVersionUID = 7316153563782823691L; /**
* Performs lock. Try immediate barge, backing up to normal
* acquire on failure.
*/
final void lock() {
// 通过判断当前线程是否获取锁的线程来决定获取操作是否成功,如果同步状态值成功修改,那就代表当前线程获取到了锁
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);
}
// 调用的是父类Sync的尝试获取锁的方法
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
}

释放锁

unlock 释放锁的方法,底层调用的是 Sync 同步器的 release 方法,release 是 AQS 的方法,分成两步:

  1. 尝试释放锁,如果释放失败,直接返回 false;
  2. 释放成功,从同步队列的头节点的下一个节点开始唤醒,让其去竞争锁。

第一步就是我们上文中 Sync 的 tryRelease 方法(4.1),第二步 AQS 已经实现了。
释放锁通过LockSupport.unpark(s.thread);

unLock 的源码如下:

// 释放锁
public void unlock() {
sync.release(1);
}

ReentrantLock-源码解析的更多相关文章

  1. 第六章 ReentrantLock源码解析2--释放锁unlock()

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

  2. 死磕 java同步系列之ReentrantLock源码解析(二)——条件锁

    问题 (1)条件锁是什么? (2)条件锁适用于什么场景? (3)条件锁的await()是在其它线程signal()的时候唤醒的吗? 简介 条件锁,是指在获取锁之后发现当前业务场景自己无法处理,而需要等 ...

  3. ReentrantLock源码解析

    ReentrantLock 1 数据结构 从上图可以看出,ReentrantLock的功能都是通过sync这个对象提供的. public class ReentrantLock implements ...

  4. 深入浅出ReentrantLock源码解析

    ReentrantLock不但是可重入锁,而且还是公平或非公平锁,在工作中会经常使用到,将自己对这两种锁的理解记录下来,希望对大家有帮助. 前提条件 在理解ReentrantLock时需要具备一些基本 ...

  5. Java并发之ReentrantLock源码解析(二)

    在了解如何加锁时候,我们再来了解如何解锁.可重入互斥锁ReentrantLock的解锁方法unlock()并不区分是公平锁还是非公平锁,Sync类并没有实现release(int arg)方法,这里会 ...

  6. Java并发之ReentrantLock源码解析(四)

    Condition 在上一章中,我们大概了解了Condition的使用,下面我们来看看Condition再juc的实现.juc下Condition本质上是一个接口,它只定义了这个接口的使用方式,具体的 ...

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

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

  8. ReentrantLock源码解析——虽众但写

    在看这篇文章时,笔者默认你已经看过AQS或者已经初步的了解AQS的内部过程.   先简单介绍一下ReentantLock,跟synchronized相同,是可重入的重量级锁.但是其用法则相当不同,首先 ...

  9. Java并发之ReentrantLock源码解析(三)

    ReentrantLock和BlockingQueue 首先,看到这个标题,不要怀疑自己进错文章,也不要怀疑笔者写错,哈哈.本章笔者会从BlockingQueue(阻塞队列)的角度,看看juc包下的阻 ...

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

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

随机推荐

  1. Jmeter(三十三) - 从入门到精通 - Jmeter Http协议录制脚本工具-Badboy6(详解教程)

    1.简介 今天分享的就是在上一篇文章的基础上来进行讲解和分享:Badboy使用数据源Excel进行脚本参数化.然后在使用读取的参数进行对比断言. 2.具体场景 Badboy录制一个搜索的脚本,并对搜索 ...

  2. CSP-S2020初赛游记

    前一星期 感觉没怎么复习初赛啊,经常旷初赛练习赛--整天刷复赛题被老师怒斥了. zhoukangyang 天天做初赛(但是一天还是稳定做 \(2\) 道黑题),是不是要 AK 了啊(慌... 前一天 ...

  3. 数组问题:a[i][j] 和 a[j][i] 有什么区别?

    本文以一个简单的程序开头--数组赋值: int LEN = 10000; int[][] arr = new int[LEN][LEN]; for (int i = 0; i < LEN; i+ ...

  4. [日常摸鱼]bzoj1038 [ZJOI2008]瞭望塔-模拟退火/几何

    题意:给一条平面内$n$个点的折线,要求在折线上搞一个高度$h$的瞭望塔,能够看见折线上所有的点,求$h$的最小值($n \leq 300$) updata2018.1.21 正解半平面交在另一篇里面 ...

  5. MAC 安装Python3.7

    查看下python版本 macosdeMacBook:Versions macos$ cd /System/Library/Frameworks/Python.framework/Versions/ ...

  6. Numpy的学习1-创建数据基础

    1 import numpy as np 2 3 array = np.array([[1,2,3],[4,5,6]]) 4 5 print(array) 6 print('number of dim ...

  7. java基础:方法的定义和调用详细介绍,方法同时获取数组最大值和最小值,比较两个数组,数组交换最大最小值,附练习案列

    1. 方法概述 1.1 方法的概念 方法(method)是将具有独立功能的代码块组织成为一个整体,使其具有特殊功能的代码集 注意: 方法必须先创建才可以使用,该过程成为方法定义 方法创建后并不是直接可 ...

  8. Python 写了一个批量生成文件夹和批量重命名的工具

    Python 写了一个批量生成文件夹和批量重命名的工具 目录 Python 写了一个批量生成文件夹和批量重命名的工具 演示 功能 1. 可以读取excel内容,使用excel单元格内容进行新建文件夹, ...

  9. CCNP之MERG实验报告

    MGRE实验报告 一.实验要求: 1.R5为ISP,只能配置IP地址 2.R1--R3间建立MGRE环境,且使用EIGRP来学习各自环回 3.R4可以正常访问R5的环回 4.R1与R5进行chap认证 ...

  10. 【进程/作业管理】篇章一:Linux进程及其管理(系统监控类工具)----glances、dstat

    glances   dstat   glances命令详解 相对于htop工具的使用,这里介绍一下glances工具的使用,我个人是比较喜欢这款工具的,主要就是由于glances这款工具可以将系统状态 ...