1.ReentrantLock是基于AQS实现的一种重入锁。

2.先介绍下公平锁/非公平锁

公平锁

  • 公平锁是指多个线程按照申请锁的顺序来获取锁。

非公平锁

  • 非公平锁是指多个线程获取锁的顺序并不是按照申请锁的顺序,有可能后申请的线程比先申请的线程优先获取锁。有可能,会造成优先级反转或者饥饿现象。

3.重入锁/不可重入锁

可重入锁:广义上的可重入锁指的是可重复可递归调用的锁,在外层使用锁之后,在内层仍然可以使用,并且不发生死锁(前提得是同一个对象或者class),这样的锁就叫做可重入锁。

不可重入锁:不可重入锁,与可重入锁相反,不可递归调用,递归调用就发生死锁。

4.统一入口

 //获取锁。
@Override
public void lock() {
sync.lock();
} //获取锁,响应中断
@Override
public void lockInterruptibly() throws InterruptedException {
sync.acquireInterruptibly();
} //仅在调用时锁未被另一个线程保持的情况下,才获取该锁。
@Override
public boolean tryLock() {
return sync.nonfairTryAcquire();
} //如果锁在给定等待时间内没有被另一个线程保持,且当前线程未被 中断,则获取该锁。
@Override
public boolean tryLock(long timeout, TimeUnit unit)
throws InterruptedException {
return sync.tryAcquireNanos(, unit.toNanos(timeout));
} //试图释放此锁。
@Override
public void unlock() {
sync.release();
}

ReentrantLock默认是非公平模式,可以通过构造函数指定模式。

/**
* 构造函数,默认非公平锁
*/
public ReentrantLock() {
sync = new NonfairSync();
} /**
* 构造函数,通过布尔参数设置是否是公平锁
* @param fair
*/
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}

4.非公平模式的加锁和解锁

加锁:

//获取锁。
@Override
public void lock() {
sync.lock();
}

然后调用NonfairSync的lock方法:

/**
* 加锁
*/
@Override
final void lock() {
//以cas方式尝试将AQS中的state从0更新为1
if (compareAndSetState(, )) {
//获取锁成功则将当前线程标记为持有锁的线程,然后直接返回
setExclusiveOwnerThread(Thread.currentThread());
} else {
acquire();
}
}

如果设置state失败,则调用NonfairSync的tryAcquire方法

@Override
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}

然后调用Sync的nonfairTryAcquire方法:

/**
* 非公平模式的情况下获取同步状态
* @param acquires
* @return
*/
final boolean nonfairTryAcquire(int acquires) {
//获取当前线程实例
final Thread current = Thread.currentThread();
//获取同步state变量的值,即当前锁被重入的次数
int c = getState();
//state为0,说明当前锁未被任何线程持有
if (c == ) {
//以cas方式获取锁
if (compareAndSetState(, acquires)) {
//将当前线程标记为持有锁的线程
setExclusiveOwnerThread(current);
//获取锁成功,非重入
return true;
}
//当前线程就是持有锁的线程,说明该锁被重入了,实现重入
} else if (current == getExclusiveOwnerThread()) {
//计算state变量要更新的值
int nextc = c + acquires;
if (nextc < ) // overflow
throw new Error("Maximum lock count exceeded");
//非同步方式更新state值
setState(nextc);
//获取锁成功,重入
return true;
}
//尝试获取锁失败
return false;
}

这边体现了锁的重入,用state的次数表示锁被线程重入了state次。

else if (current == getExclusiveOwnerThread()) {
//计算state变量要更新的值
int nextc = c + acquires;
if (nextc < ) // overflow
throw new Error("Maximum lock count exceeded");
//非同步方式更新state值
setState(nextc);
//获取锁成功,重入
return true;
}

解锁

//试图释放此锁。
@Override
public void unlock() {
sync.release();
}

然后调用Sync的tryRelease方法:

/**
* 释放同步状态
* @param releases
* @return
*/
@Override
protected final boolean tryRelease(int releases) {
//计算待更新的state值
int c = getState() - releases;
//判断当前线程是否独占
if (Thread.currentThread() != getExclusiveOwnerThread()) {
throw new IllegalMonitorStateException();
}
//是否释放同步状态成功的标志
boolean free = false;
//待更新的state值为0,说明持有锁的线程未重入,一旦释放锁其他线程将能获取
if (c == ) {
free = true;
//清除锁的持有线程标记
setExclusiveOwnerThread(null);
}
//更新state值
setState(c);
return free;
}
 锁的最终释放要去锁对于获取进行计数自增,计算表示当前锁被重复获取的次数,而锁被释放时,计数自减,当计数为0时表示已经释放成功。

5.公平模式的加锁和解锁

加锁:

@Override
protected final boolean tryAcquire(int acquires) {
//获取当前线程实例
final Thread current = Thread.currentThread();
//获取同步state变量的值,即当前锁被重入的次数
int c = getState();
//state为0,说明当前锁未被任何线程持有
if (c == ) {
/**
* 1.判断同步队列中当前节点是否有前驱节点
* 2. 以cas方式获取锁
*/
if (!hasQueuedPredecessors() &&
compareAndSetState(, acquires)) {
//将当前线程标记为持有锁的线程
setExclusiveOwnerThread(current);
return true;
}
//当前线程就是持有锁的线程,说明该锁被重入了,实现重入
} else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < )
throw new Error("Maximum lock count exceeded");
//非同步方式更新state值
setState(nextc);
//获取锁成功,重入
return true;
}
//尝试获取锁失败
return false;
}

对于非公平锁,只要cas设置同步状态成功,则表示当前线程获取了锁,而公平锁则不同,公平锁的获取增加了hasQueuedPredecessors的判断,即加入了判断同步队列中当前节点是否有前驱节点,

如果返回true,则表示有线程比当前线程更早滴请求获取锁,因此需要等待前驱线程获取并释放锁之后才能继续获取锁。

锁:同公平锁的解锁方式

 

 

ReentrantLock(重入锁)简单源码分析的更多相关文章

  1. ReentrantLock(重入锁)的源码解析

    转自:从源码角度彻底理解ReentrantLock(重入锁)](https://www.cnblogs.com/takumicx/p/9402021.html)) 公平锁内部是FairSync,非公平 ...

  2. 从源码角度彻底理解ReentrantLock(重入锁)

    目录 1.前言 2.AbstractQueuedSynchronizer介绍 2.1 AQS是构建同步组件的基础 2.2 AQS的内部结构(ReentrantLock的语境下) 3 非公平模式加锁流程 ...

  3. java并发系列(四)-----源码角度彻底理解ReentrantLock(重入锁)

    1.前言 ReentrantLock可以有公平锁和非公平锁的不同实现,只要在构造它的时候传入不同的布尔值,继续跟进下源码我们就能发现,关键在于实例化内部变量sync的方式不同,如下所示: /** * ...

  4. ReentrantLock 锁释放源码分析

    ReentrantLock 锁释放源码分析: 调用的是unlock 的方法: public void unlock() { sync.release(1); } 接下来分析release() 方法: ...

  5. java高并发系列 - 第12天JUC:ReentrantLock重入锁

    java高并发系列 - 第12天JUC:ReentrantLock重入锁 本篇文章开始将juc中常用的一些类,估计会有十来篇. synchronized的局限性 synchronized是java内置 ...

  6. JUC之线程池基础与简单源码分析

    线程池 定义和方法 线程池的工作时控制运行的线程数量,处理过程中将任务放入队列,然后在线程创建后启动这些任务,如果线程数量超过了最大数量,超出数量的线程排队等候,等待其他线程执行完成,再从队列中取出任 ...

  7. ReentrantLock(重入锁)以及公平性

    ReentrantLock(重入锁)以及公平性 标签(空格分隔): java NIO 如果在绝对时间上,先对锁进行获取的请求一定被先满足,那么这个锁是公平的,反之,是不公平的,也就是说等待时间最长的线 ...

  8. ReentrantLock重入锁详解

    1.定义 重入锁:能够支持一个线程对资源的重复加锁,也就是当一个线程获取到锁后,再次获取该锁时而不会被阻塞. 2.可重入锁的应用场景 2.1 如果已经加锁,则不再重复加锁,比如:交互界面点击后响应时间 ...

  9. Java多线程之ReentrantLock重入锁简介与使用教程

    转载请注明原文地址:http://www.cnblogs.com/ygj0930/p/6543947.html  我们知道,线程安全问题需要通过线程之间的同步来解决,而同步大多使用syncrhoize ...

随机推荐

  1. linux-3.2.36内核启动2-setup_arch中的内存初始化1(arm平台 分析高端内存和初始化memblock)【转】

    转自:http://blog.csdn.net/tommy_wxie/article/details/17093307 上一篇微博留下了这几个函数,现在我们来分析它们         sanity_c ...

  2. pexpect模块

    pexpect用来启动子程序,使用正则表达式对程序输出做出特定响应,以此实现与其自动交互的python模块,当然我们可以使用他来做ssh登陆,ssh模块登陆还有一个基于python实现远程连接,用于s ...

  3. AC日记——货车运输 codevs

    3287 货车运输 2013年NOIP全国联赛提高组  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 钻石 Diamond 题解  查看运行结果     题目描述 Descri ...

  4. Codeforces Gym101572 B.Best Relay Team (2017-2018 ACM-ICPC Nordic Collegiate Programming Contest (NCPC 2017))

    2017-2018 ACM-ICPC Nordic Collegiate Programming Contest (NCPC 2017) 今日份的训练,题目难度4颗星,心态被打崩了,会的算法太少了,知 ...

  5. SQLite的sqlite_sequence表

    SQLite的sqlite_sequence表   sqlite_sequence表也是SQLite的系统表.该表用来保存其他表的RowID的最大值.数据库被创建时,sqlite_sequence表会 ...

  6. Java生成GUID的方法

    其实在Java上已经换了一个说法,叫做UUID,方法如下: java.util.UUID.randomUUID()

  7. Oracle8i Internal Services

    http://d.hatena.ne.jp/yohei-a/20091017/1255791152 第1回 Oracle8i Internal Services 1人読書会 Oracle 読んだところ ...

  8. [c++菜鸟]《Accelerate C++》习题解答

    第0章 0-0 编译并运行Hello, world! 程序. #include <iostream> using namespace std; int main() { cout < ...

  9. Cocos2d-x学习笔记(18)(TestCpp源代码分析-2)

    本章主要讲controller.h/cpp文件的分析,该文件主要用于演示样例场景管理类TestController,用于显示全部演示样例的菜单. //controller.cpp #include & ...

  10. project管理之makefile与自己主动创建makefile文件过程

    (风雪之隅 http://www.laruence.com/2009/11/18/1154.html) Linux Makefile自己主动编译和链接使用的环境 想知道到Linux Makefile系 ...