java多线程系列6 synchronized 加强版 ReentrantLock
ReentrantLock类是可重入、互斥、实现了Lock接口的锁,它与使用synchronized方法和快具有相同的基本行为和语义,并且扩展了其能力。ReenreantLock类的常用方法有:
ReentrantLock() : 创建一个ReentrantLock实例
ReentrantLock(boolean fair) 是否是公平锁,默认不是 【实际开发中 一般不开启公平】
lock() : 获得锁
unlock() : 释放锁
下面代码演示 ReentrantLock 实现的累加器
public class RentLack implements Runnable {
ReentrantLock lock = new ReentrantLock();
private int count = 0;
public int getCount()
{
return count;
}
@Override
public void run() {
for (int i = 0; i < 10000; i++) {
lock.lock();
try {
count++;
} finally {
lock.unlock(); //释放锁一定要写在finally里面
}
}
}
public static void main(String[] args) throws Exception {
RentLack rentLack = new RentLack();
Thread t1 = new Thread(rentLack);
Thread t2 = new Thread(rentLack);
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println(rentLack.getCount());
}
}
原理解析 ----------
说道ReentrantLock,不得不谈AbstractQueuedSynchronized(AQS抽象的队列式的同步器),
AQS定义了一套多线程访问共享资源的同步器框架,许多同步类实现都依赖于它,如常用的ReentrantLock/Semaphore/CountDownLatch...。
-----深入了解AQS 请google相关信息
当我们调用 ReentrantLock lock = new ReentrantLock(); 看看具体是怎么做的?
private final Sync sync;
public ReentrantLock() {
sync = new NonfairSync();
}
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}
可以看到,它调用是 上面两个类 他们的关系如下

ReentrantLock实现了Lock接口,获取锁是通过lock方法来实现的。
那当我们调用lock的时候,具体都做了什么呢? 这里只分析不公平方式。
具体代码如下
final void lock() {
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);
}
=======
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
==========
下来看看 非公平的方式的tryAcquire
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();
//state字段,在ReentrantLock中表示锁被持有的次数,它是一个volatile类型的整型值,因此对它的修改可以保证其他线程可以看到
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;
}
执行流程如下
如果没有线程占有该资源,直接当前线程占有。
如果占用了,执行acquire(1)
- 调用tryAcquire()尝试直接去获取资源,如果成功则直接返回;
- 获取失败,则addWaiter()将该线程加入等待队列
- acquireQueued()使线程在等待队列中休息,有机会时(轮到自己,会被unpark())会去尝试获取资源。获取到资源后才返回。如果在整个等待过程中被中断过,则返回true,否则返回false。
4.自我中断
在tryAcquire方法中可以看到,同一个线程获得锁以后可以多次重入,但是需要多次unlock哈。tryAcquire执行流程如下
1、首先判断锁有没有被持有,如果被持有,就判断持有锁的线程是不是当前线程,如果不是就啥也不做,返回获取失败,如果是就增加重入数,返回成功获取;
2、如果锁没有被任何线程持有(c==0),直接将当前线程设置为锁的持有者。
======================
总结:关于 synchronized , ReentrantLock 究竟用谁的问题?
synchronized 能解决的问题,ReentrantLock 都能解决 。
在性能上,Jdk8 对synchronized进行了优化,性能上差别不大。
java多线程系列6 synchronized 加强版 ReentrantLock的更多相关文章
- java多线程系列(五)---synchronized ReentrantLock volatile Atomic 原理分析
java多线程系列(五)---synchronized ReentrantLock volatile Atomic 原理分析 前言:如有不正确的地方,还望指正. 目录 认识cpu.核心与线程 java ...
- java多线程系列之 synchronized
一.synchronized基本原理 java的内置锁:每个java对象都可以用做一个实现同步的锁,这些锁成为内置锁.线程进入同步代码块或方法的时候会自动获得该锁,在退出同步代码块或方法时会释放该锁. ...
- Java多线程系列3 synchronized 关键词
先来看一个线程安全的例子 ,两个线程对count进行累加,共累加10万次. public class AddTest { public static void main(String[] args) ...
- java多线程系列 目录
Java多线程系列1 线程创建以及状态切换 Java多线程系列2 线程常见方法介绍 Java多线程系列3 synchronized 关键词 Java多线程系列4 线程交互(wait和 ...
- java多线程系列(四)---ReentrantLock的使用
Lock的使用 前言:本系列将从零开始讲解java多线程相关的技术,内容参考于<java多线程核心技术>与<java并发编程实战>等相关资料,希望站在巨人的肩膀上,再通过我的理 ...
- Java多线程系列--“JUC锁”02之 互斥锁ReentrantLock
本章对ReentrantLock包进行基本介绍,这一章主要对ReentrantLock进行概括性的介绍,内容包括:ReentrantLock介绍ReentrantLock函数列表ReentrantLo ...
- Java多线程系列--“基础篇”04之 synchronized关键字
概要 本章,会对synchronized关键字进行介绍.涉及到的内容包括:1. synchronized原理2. synchronized基本规则3. synchronized方法 和 synchro ...
- Java多线程系列--“JUC锁”03之 公平锁(一)
概要 本章对“公平锁”的获取锁机制进行介绍(本文的公平锁指的是互斥锁的公平锁),内容包括:基本概念ReentrantLock数据结构参考代码获取公平锁(基于JDK1.7.0_40)一. tryAcqu ...
- Java多线程系列--“JUC锁”04之 公平锁(二)
概要 前面一章,我们学习了“公平锁”获取锁的详细流程:这里,我们再来看看“公平锁”释放锁的过程.内容包括:参考代码释放公平锁(基于JDK1.7.0_40) “公平锁”的获取过程请参考“Java多线程系 ...
随机推荐
- makefile或shell中的一些变量
总是记不住,作个笔记 $@ 所有目标文件 $< 第一个依赖文件的名称 $? 所有的依赖文件,以空格分开,这些依赖文件的修改日期比目标的创建日期晚 $^ 所有的依赖文件,以空格分开,不包含重复的依 ...
- Android Dialog.dismiss()与Activity.finish()顺序
activity.finish() 和dialog.show() 同时调用的时候, 需要先调用dialog.dismiss() 后activity.finish() 如果先直接finish()后,再触 ...
- DokuWiki 命名空间管理
为了更好的组织结构,Dokuwiki提供了命名空间这个功能,那怎么管理命名空间的,其实可以安装插件去管理 Add New Page Plugin:新建界面 https://www.dokuwiki.o ...
- python if not
判断是否为None的情况 if not x if x is None if not x is None if x is not None`是最好的写法,清晰,不会出现错误,以后坚持使用这种写法. 使用 ...
- 数据访问安全--数据库遮罩及断词 Data Masking & Tokenization
现在大数据时代几乎无隐私,各政府部门各公司都要求实名制(动不动手机认证,身份证号码认证),但又无力确保数据安全,称为乱象. 其实在2011年,我们就接触过数据库遮罩断词产品,一个澳大利亚公司产品. 简 ...
- 八(第二篇)、主体结构元素——nav元素、aside元素
nav元素 nav元素是一个可以用作页面导航的链接组,其中的导航元素链接到其他页面或当前页面的其他部分. 并不是所有的链接组都要被放进nav元素,只需要将主要的.基本的链接组放进nav元素即可. na ...
- Redis管理:安全/耗时命令日志与命令监控/数据库管理工具
1.安全管理 1)绑定指定IP Redis的安全设计是在“Redis运行在可信环境”这个前提之下的,在生产环境中建议通过应用程序连接Redis.Redis可以配置只接受来自指定IP的的请求,可通过修改 ...
- nodejs通过mocha处理运行文件路径下所有js文件
1.获取文件路径: 方式一:整个js文件使用 var path=require('path');var public_path=path.resolve('../testcase/listData/* ...
- python 如何把小数变成百分数格式
1. 数据样本 ,valid_rate,homework_rate,inter_rate,playback_rate,zhujiang_good_comment5_rate,fudao_good_co ...
- web和app的简单测试区别和工具介绍
首先说一下我对Web自动化测试与CS自动化测试的认识.从宏观对比都是通过脚本自动化完成功能的验证,区别不大.Web测试更为显著的浏览器兼容性.安全,以及与Web技术相关的表单测试.链接测试等,其实都是 ...