ReentrantLock概述

ReentrantLock是Lock接口的实现类,可以手动的对某一段进行加锁。ReentrantLock可重入锁,具有可重入性,并且支持可中断锁。其内部对锁的控制有两种实现,一种为公平锁,另一种为非公平锁。ReentrantLock的实现原理为volatile+CAS

ReentrantLock可重入性

ReentrantLock具有可重入性,可重入性是指当一个线程拥有一个方法的锁以后,是否还可以进入该方法,一般这种情况出现在递归中。ReentrantLock的可重入性是基于Thread.currentThread()实现的,是线程粒度的,也就是说当前线程获得一个锁以后,当前线程的所有方法都可以获得这个锁。Reentrant依赖的锁只有两种实现类,NonFairSync和FairSync,但是它们获取锁的方式大同小异。一下是公平锁的获取实现。ReentrantLock.FairSync.tryAcquire

 protected final boolean tryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
//每一次加锁state+1
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;
}
}

ReentrantLock锁的实现分析

ReentrantLock有两种锁的实现,FairSync和NonFairSync,对于这两种锁,他们获取锁的方式都大同小异ReentrantLock$Sync#acquire

    public final void acquire(int arg) {
//通过tryAcquire去尝试获取锁,公平锁和非公平锁有不同的实现
if (!tryAcquire(arg) &&
//如果没有获取到,就将该线程加入等待队列,然后循环尝试获取该锁
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
//如果尝试获取锁的次数达到一定次数,就会触发中断,中断该线程,并释放锁
selfInterrupt();
}

tryAcquire():尝试获取锁;

addWaiter():将线程加入等待队列

acquireQueued():在多次循环中尝试获取到锁或者将当前线程堵塞

selfInterrupt():如果多次未获取成功,将中断该线程(避免死锁)

公平锁(FairSync)

公平锁内部维护了一个等待获取该锁的线程的队列,会按照队列顺序给每个线程锁。每当抢占锁的时候,就会判断是否有等待队列,如果有等待队列,就从等待队列的头开始分配锁

         protected final boolean tryAcquire(int acquires) {
//取得当前请求锁的线程
final Thread current = Thread.currentThread();
//取得stage,每一次加锁,stage都会+1,如果stage是0,就说明,没有人使用该锁
int c = getState();
if (c == 0) {
//如果没有等待队列,并且CAS通过,就将当前线程就抢到了锁
if (!hasQueuedPredecessors() &&
compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
//如果锁没有释放,就判断当前线程是否是该锁的拥有者,如果是,可以直接使用该改,并stage+1
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < 0)
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
//如果没有抢到锁,就返回false
return false;
}

非公平锁(NonFairSync)

非公平锁在抢占锁时,会进行随机抢占,后抢占的线程往往抢占到的几率比较大。

 if (c == 0) {
//非公平锁仅仅是使用CAS,并不会去查看队列(也没有队列)
if (compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}

ReentrantLock的内存可见性

ReentrantLock保证内存可见性,作用和synchronized一样,但是要比synchronized更加灵活,方便,ReentrantLock可以和Condition联合使用

ReentrantLock详解的更多相关文章

  1. Lock的实现之ReentrantLock详解

    摘要 Lock在硬件层面依赖CPU指令,完全由Java代码完成,底层利用LockSupport类和Unsafe类进行操作: 虽然锁有很多实现,但是都依赖AbstractQueuedSynchroniz ...

  2. java之ReentrantLock详解

    前言 如果一个代码块被synchronized修饰了,当一个线程获取了相应的锁,并执行该代码块时,其他线程便只能一直等待,等待获取锁的释放,现在有这么一种情况,这个获取锁的线程由于要等待IO或者其他原 ...

  3. ReentrantLock 详解

    ReentrantLock的功能是实现代码段的并发访问控制,也就是通常意义上所说的锁,java中实现锁有两种方式,一种是本文所提的ReentrantLock,另一种是synchronized.Reen ...

  4. ReentrantLock详解 以及与synchronized的区别

    ReentrantLock lock = new ReentrantLock(); //参数默认false,不公平锁 ReentrantLock lock = new ReentrantLock(tr ...

  5. Java并发之ReentrantLock详解

    一.入题 ReentrantLock是Java并发包中互斥锁,它有公平锁和非公平锁两种实现方式,以lock()为例,其使用方式为: ReentrantLock takeLock = new Reent ...

  6. 图解AQS原理之ReentrantLock详解-非公平锁

    概述 并发编程中,ReentrantLock的使用是比较多的,包括之前讲的LinkedBlockingQueue和ArrayBlockQueue的内部都是使用的ReentrantLock,谈到它又不能 ...

  7. 从ReentrantLock详解AQS原理源码解析

    数据结构 java.util.concurrent.locks.AbstractQueuedSynchronizer类中存在如下数据结构. // 链表结点 static final class Nod ...

  8. 最强Java并发编程详解:知识点梳理,BAT面试题等

    本文原创更多内容可以参考: Java 全栈知识体系.如需转载请说明原处. 知识体系系统性梳理 Java 并发之基础 A. Java进阶 - Java 并发之基础:首先全局的了解并发的知识体系,同时了解 ...

  9. java并发编程 | 锁详解:AQS,Lock,ReentrantLock,ReentrantReadWriteLock

    原文:java并发编程 | 锁详解:AQS,Lock,ReentrantLock,ReentrantReadWriteLock 锁 锁是用来控制多个线程访问共享资源的方式,java中可以使用synch ...

随机推荐

  1. Android图片处理--全景查看效果

    PS:Android对于图片处理这块资源还是挺多的,之前用OpenGL制作图片的全景效果,耗时耗力,而且只能点击进去后看到,但是效果是非常的号,今天所写的是编写好的一个图片控件,只要拿来用就可以了.效 ...

  2. 【转】JavaScript 简史

    本文来自众成翻译.JavaScript 毋庸置疑是当今最重要的语言之一.Web 的兴起已经把 JavaScript 带到一个前所未有的地步.下面我们来看看 JavaScript 在其短短历史中是如何演 ...

  3. selenium(2.4.0)中不能导出web drive 代码

    最近在学习selenium.要做web自动化测试.咱只会C# .就想了,这个测试用例要是能用C# 控制,保存起来,就可以以后自动运行了,不用每次点击运行了. 看了看它的文档,就开始试验了,录脚本折腾了 ...

  4. 微信小程序国际化

    微信小程序国际化 现状 小程序国际化官方没有支持,也没有现成的插件. 网上有人做了国际化的尝试.但是只能替换静态文本,就是简单的键值匹配. vue-i18n 由于是基于html 和 vue, 不同于w ...

  5. IOS 本地推送(UILocalNotification)

    推送通知 ● 注意:这里说的推送通知跟NSNotification有所区别 • NSNotification是抽象的,不可见的 • 推送通知是可见的(能用肉眼看到) ● iOS中提供了2种推送通知 ● ...

  6. 每天一个linux命令(22):tar命令

    通过SSH访问服务器,难免会要用到压缩,解压缩,打包,解包等,这时候tar命令就是是必不可少的一个功能强大的工具.linux中最流行的tar是麻雀虽小,五脏俱全,功能强大. tar命令可以为linux ...

  7. Zookeep启动异常:Error contacting service. It is probably not running.

    异常提示: [root@hadoop bin]# ./zkServer.sh status JMX enabled by default Using config: /usr/local/zk/bin ...

  8. 【洛谷P2607】[ZJOI2008]骑士

    骑士 题目链接 这道题一看,似乎和舞会是一样的,然而它并没有保证是一棵树 但是,对于每个连通块,必有相同的点数和边数,这样的图一定是一棵树上加一条边 这条边一定回使图中形成一个环,这种图貌似叫“基环树 ...

  9. java递归菜单树转换成pojo对象

    package com.cjonline.foundation.authority.pojo; import java.util.ArrayList; import java.util.Collect ...

  10. 解决Storm 和yarn 8080 端口冲突

    本机装了Yarn和Storm后,启动Storm后,发现NodeMange无法启动,找了下没找着在哪修改.只好修改Storm的配置,在配置上添加 ui.port: "9999" 再启 ...