1.定义

ReentrantLock是一种可重入锁,允许一个线程对同一个资源重复加锁,如果说是当一个线程调用一个锁的lock()方法,然后再次调用锁的lock()方法,当锁不支持可重入时,该线程会被自己所阻塞。该锁还能支持公平锁和非公平锁的选择,公平的意思就是将锁分配给等待锁时间最长的线程,这样可以避免饥饿情况的发生,但是造成线程大量的上下文切换,影响吞吐量。

从ReentrantLock的类定义来看,该锁实现了Lock和Serializable接口。

public class ReentrantLock implements Lock, java.io.Serializable

2.ReentrantLock的具体实现

ReentrantLock通过将继承AQS的子类sync作为类成员变量来实现锁,sync实现AQS的抽象方法来管理同步状态。

(1)Sync静态内部类

  //AQS的子类。
private final Sync sync; //Sync也是一个抽象类,因为锁有非公平和公平的区别。
abstract static class Sync extends AbstractQueuedSynchronizer {
private static final long serialVersionUID = -5179523762034025860L; //非公平和公平锁的lock()方法有不同的实现。
abstract void lock();

//tryLock()在子类中实现,该方法是非公平的独占式获取同步状态。
//该方法首先判断同步状态是否被获取,如果没有,CAS获取同步状态并将锁的拥有者设为当前线程,如果有,判断获取锁的线程是否是当前线程,如果是,将同步值进行累加。
//成功获取锁的线程,再次获取锁,只是增加了同步值。
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
if (compareAndSetState(0, acquires)) {
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;
}

//获取了多少次锁,同样也要释放多少次锁。
//当同步值不为0时,还是当前线程占有锁。
protected final boolean tryRelease(int releases) {
int c = getState() - releases;
if (Thread.currentThread() != getExclusiveOwnerThread())
throw new IllegalMonitorStateException();
boolean free = false;
if (c == 0) {
free = true;
setExclusiveOwnerThread(null);
}
setState(c);
return free;
}

//是否被当前线程所占有
protected final boolean isHeldExclusively() {
return getExclusiveOwnerThread() == Thread.currentThread();
} final ConditionObject newCondition() {
return new ConditionObject();
} //得到锁的占有者
final Thread getOwner() {
return getState() == 0 ? null : getExclusiveOwnerThread();
}
//获取锁的次数
final int getHoldCount() {
return isHeldExclusively() ? getState() : 0;
}

     //锁是否被获取
final boolean isLocked() {
return getState() != 0;
} //反序列化操作
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
s.defaultReadObject();
setState(0); // reset to unlocked state
}
}

(2)NonfairSync和FairSync

ReentrantLock是支持公平锁和非公平锁的,而公平锁和非公平锁的具体实现是依靠AQS的抽象子类Sync的不同子类实现(NonfairSync和FairSync)。

    //非公平锁的实现
static final class NonfairSync extends Sync {
private static final long serialVersionUID = 7316153563782823691L; //非公平锁加锁,acquire调用tryAcquire,tryAcquire调用nonfairTryAcquire
final void lock() {
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);
} protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
} //公平锁的实现
static final class FairSync extends Sync {
private static final long serialVersionUID = -3000897897090466540L; final void lock() {
acquire(1);
} //lock()调用acquire(),acquire()调用tryAcquire(),公平锁和非公平锁的tryAcquire()的实现唯一不同
//就是加入了hasQueuesPredecessors(),通过判断当前节点是否有前驱节点,如果有则当前节点不是等待时间最长的线程
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;
}
}

公平锁和非公平锁的主要在于两个地方:

1.获取锁lock()方法的不同:非公平锁会直接进行一次CAS,如果CAS成功,就直接获取锁了。

2.tryAcquire()方法实现的不同:当同步状态此时被释放的时候,state等于0,并没有任何线程占有锁,如果是公平锁,会判断队列中是否有线程等待获取锁,如果有的话,直接将自己构造成一个节点加入同步队列,但是非公平锁会直接CAS设置状态,不考虑同步队列中是否有其他线程等待获取锁。如果获取同步状态失败,会将自己构造成一个节点加入同步队列中,加入同步队列之后,等待前驱节点释放同步状态,唤醒自己,这后面的步骤公平锁和非公平锁是一样的。

3.ReentrantLock的主要方法

  //构造函数默认是非公平锁
public ReentrantLock() {
sync = new NonfairSync();
} //可选择实现公平锁
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
} //获取锁
public void lock() {
sync.lock();
} //可中断式的获取锁
public void lockInterruptibly() throws InterruptedException {
sync.acquireInterruptibly(1);
} //尝试非阻塞的获取锁,调用方法之后立马返回,能获取返回true,不能获取返回false
public boolean tryLock() {
return sync.nonfairTryAcquire(1);
} //释放锁
public void unlock() {
sync.release(1);
} //获取等待通知组件,该组件和当前锁绑定
public Condition newCondition() {
return sync.newCondition();
} //锁被获取的次数
public int getHoldCount() {
return sync.getHoldCount();
} //锁是否被当前线程所占有
public boolean isHeldByCurrentThread() {
return sync.isHeldExclusively();
} //锁是否已经被获取
public boolean isLocked() {
return sync.isLocked();
} //是否是公平锁
public final boolean isFair() {
return sync instanceof FairSync;
} //获取锁的所有者
protected Thread getOwner() {
return sync.getOwner();
} //是否有线程等待该锁
public final boolean hasQueuedThreads() {
return sync.hasQueuedThreads();
} //查询给定线程是否在等待该锁
public final boolean hasQueuedThread(Thread thread) {
return sync.isQueued(thread);
} //查询等待锁的线程数
public final int getQueueLength() {
return sync.getQueueLength();
} //返回等待锁的线程集合
protected Collection<Thread> getQueuedThreads() {
return sync.getQueuedThreads();
}

4.ReentrantLock总结

聚合关系总结:

(1)ReentrantLock实现了Lock,Serializable接口

(2)ReentrantLock.Sync(内部类)继承了AQS

(3)ReentrantLock.NonfairSync和ReentrantLock.FairSync继承了ReentrantLock.Sync

(4)ReentrantLock持有ReentrantLock.Sync对象(实现锁功能)

性质:

(1)独占锁(排它锁):只能有一个线程获取锁

(2)重入锁:一个线程可以多次lock()

(3)公平/非公平锁:只针对上锁过程

(4)非公平锁:尝试获取锁,若成功立刻返回,失败则加入同步队列

(5)公平锁:直接加入同步队列

 

JDK源码之ReentrantLock的更多相关文章

  1. 【JDK】JDK源码分析-ReentrantLock

    概述 在 JDK 1.5 以前,锁的实现只能用 synchronized 关键字:1.5 开始提供了 ReentrantLock,它是 API 层面的锁.先看下 ReentrantLock 的类签名以 ...

  2. JDK源码分析—— ArrayBlockingQueue 和 LinkedBlockingQueue

    JDK源码分析—— ArrayBlockingQueue 和 LinkedBlockingQueue 目的:本文通过分析JDK源码来对比ArrayBlockingQueue 和LinkedBlocki ...

  3. [源码分析]ReentrantLock & AbstractQueuedSynchronizer & Condition

    首先声明一点: 我在分析源码的时候, 把jdk源码复制出来进行中文的注释, 有时还进行编译调试什么的, 为了避免和jdk原生的类混淆, 我在类前面加了"My". 比如把Reentr ...

  4. 【并发编程】【JDK源码】J.U.C--AQS (AbstractQueuedSynchronizer)(1/2)

    J.U.C实现基础 AQS.非阻塞数据结构和原子变量类(java.util.concurrent.atomic包中的类),concurrent包中的基础类都是使用这种模式来实现的.而concurren ...

  5. 【并发编程】【JDK源码】J.U.C--AQS 及其同步组件(2/2)

    原文:慕课网高并发实战(七)- J.U.C之AQS 在[并发编程][JDK源码]AQS (AbstractQueuedSynchronizer)(1/2)中简要介绍了AQS的概念和基本原理,下面继续对 ...

  6. JDK源码阅读顺序

      很多java开发的小伙伴都会阅读jdk源码,然而确不知道应该从哪读起.以下为小编整理的通常所需阅读的源码范围. 标题为包名,后面序号为优先级1-4,优先级递减 1.java.lang 1) Obj ...

  7. JDK源码分析之concurrent包(二) -- 线程池ThreadPoolExecutor

    上一篇我们简单描述了Executor框架的结构,本篇正式开始并发包中部分源码的解读. 我们知道,目前主流的商用虚拟机在线程的实现上可能会有所差别.但不管如何实现,在开启和关闭线程时一定会耗费很多CPU ...

  8. 【JDK】JDK源码分析-AbstractQueuedSynchronizer(1)

    概述 前文「JDK源码分析-Lock&Condition」简要分析了 Lock 接口,它在 JDK 中的实现类主要是 ReentrantLock (可译为“重入锁”).ReentrantLoc ...

  9. 【JDK】JDK源码分析-AbstractQueuedSynchronizer(2)

    概述 前文「JDK源码分析-AbstractQueuedSynchronizer(1)」初步分析了 AQS,其中提到了 Node 节点的「独占模式」和「共享模式」,其实 AQS 也主要是围绕对这两种模 ...

随机推荐

  1. mosquitto SSL认证

    [11]MQTT mosquitto 双向SSL认证配置方式 [12]MQTT mosquitto 单向SSL认证的配置方式 Mosquitto服务器的搭建以及SSL/TLS安全通信配置(比较可信) ...

  2. 【设计模式】用追MM来解释23种设计模式,转

    创建型模式 1.FACTORY—追MM少不了请吃饭了,麦当劳的鸡翅和肯德基的鸡翅都是MM爱吃的东西,虽然口味有所不同,但不管你带MM去麦当劳或肯德基,只管向服务员说“来四个鸡翅”就行了.麦当劳和肯德基 ...

  3. 对接口(interface)的思考

    接口,java中用关键字interface定义.今天学习java基础API时,发现一个特点:每个包中都定义了一堆的接口,感觉有马克思主义中提到的“上层建筑”的味道.接口就是为需要实现的功能定一个基调, ...

  4. [附POC]Apache Struts2最新(CVE-2017-5638,S02-45)POC

    #! /usr/bin/env python # encoding:utf-8 import urllib2 import sys from poster.encode import multipar ...

  5. 家庭记账本之Github账号注册与安装(二)

    好多程序猿都在使用github用来存放自己的代码:但是如果仅仅用github的web版本的话:有一些功能还是需要使用git客户端工具才能操作的: 那么今天将指导大家如何安装GitHub for win ...

  6. centos make error: fatal error: curses.h: No such file or directory

    yum install ncurses.x86_64 yum install ncurses-devel.x86_64 yum install ncurses-libs.x86_64 yum inst ...

  7. 获取 Google USB 驱动程序

    获取 Google USB 驱动程序       另请参阅 安装 USB 驱动程序 使用硬件设备 使用任何 Google Nexus 设备进行 ADB 调试时,只有 Windows 需要 Google ...

  8. xml文档对象模型doc

    对与DOM来说 ,一切都是节点Node; ②Document可以看成一个节点,Element可以看成一个节点,Text可以看成一个节点, 封装出来的对象都可以看成节点Node; ③在JDK中,Node ...

  9. Tomcat任意文件上传漏洞CVE-2017-12615

    文章来源:https://blog.csdn.net/qq1124794084/article/details/78044756 漏洞影响的tomcat版本为tomcat7.0.0-7.0.81版本 ...

  10. spring之继承配置

    我们有一下两个类,并且Gradate类继承了Student类 public class Student public class Gradate extends Student 在applicatio ...