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多线程系 ...
随机推荐
- <Numerical Analysis>(by Timothy Sauer) Notes
2ed, by Timothy Sauer DEFINITION 1.3A solution is correct within p decimal places if the error is l ...
- 使用docker查看jvm状态,在docker中使用jmap,jstat
Docker中查看JVM的信息: 1. 列出docker容器:docker ps 2. 标准输入和关联终端:docker exec -it 容器ID bash 3. 查找出j ...
- 第26课 可变参数模板(7)_any和variant类的实现
1. any类的实现 (1)any类: ①是一个特殊的,只能容纳一个元素的容器,它可以擦除类型,可以将何任类型的值赋值给它. ②使用时,需要根据实际类型将any对象转换为实际的对象. (2)实现any ...
- doris 0.9.0版本docker镜像制作与使用
1. 安装docker 详情请参见本人博客 2. 编译doris 详情请参见doris官网文档 3. 在编译好的doris output文件夹下编写两个Dockerfile 3.1 Dockerfi ...
- VIVADO 入门之仿真与逻辑分析仪使用
多路分频器设计 在第七节的学习中,笔者带大家通过一个入门必学的流水灯实验实现,快速掌握了VIVADO基于FPGA开发板的基本流程.考虑到很多初学者并没有掌握好Vivado 下FPGA的开发流程,本章开 ...
- css3兼容性检测工具
1. Modernizr 会在Modernizr 会在页面加载后立即检测特性:然后创建一个包含检测结果的 JavaScript 对象,同时在 html 元素加入方便你调整 CSS 的 class ...
- 关于PHP代码复用‘traits’的一段代码
附:代码摘自菜鸟教程 <?php// 定义一个类名Base对象,并带有公共函数sayHello class Base { public function sayHello() { echo 'H ...
- 事务、事务特性、事务隔离级别、spring事务传播特性
事务.事务特性.事务隔离级别.spring事务传播特性 1.什么是事务: 事务是程序中一系列严密的操作,所有操作执行必须成功完成,否则在每个操作所做的更改将会被撤销,这也是事务的原子性(要么成功, ...
- <记录> curl 封装函数
1. POST请求 参数1 : 请求地址 参数2 : 数组形式的参数 /** * @param string $url post请求地址 * @param array $params * @retur ...
- Eclipse 安装中文简体语言包
Installing the language packs Open the install wizard with 'Help' > 'Install new software...' Add ...