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多线程系 ...
随机推荐
- vagrant The specified host network collides with a non-hostonly network!
换个ip scripts\homestead.rb config.vm.network :private_network, ip: settings["ip"] ||= " ...
- OutOfMemoryError异常java内存泄漏(Memory Leak)和内存溢出(Memory Overflow)
本篇文章理解源自于<深入理解java虚拟机>2.4章节 实战:OutOfMemoryError异常 在以下例子中,所有代码都可以抛出OutOfMemoryError异常,但是要区分到底 ...
- kafka partition(分区)与 group(转)
原文 https://www.cnblogs.com/liuwei6/p/6900686.html 一. 1.原理图 2.原理描述 一个topic 可以配置几个partition,produce发送 ...
- [UE4]Tile View
一.Tile View也属于List View,Tile View以小方格的形式展示子控件. 二.Tile View.Entry Height.Tile View.Entry Width设置每个Til ...
- BasicConverter 基本数据类型转换器
package cn.ubibi.jettyboot.framework.commons; import com.alibaba.fastjson.JSON; import com.alibaba.f ...
- windows本地eclispe运行linux上hadoop的maperduce程序
继续上一篇博文:hadoop集群的搭建 1.将linux节点上的hadoop安装包从linux上下载下来(你也可以从网上直接下载压缩包,解压后放到自己电脑上) 我的地址是: 2.配置环境变量: HAD ...
- element-vue-koa2-mysql实现文件上传
友情提示:这篇博客不会详细说明搭建过程 阅读群体建议:第一次使用node或者koa2写文件上传或者下载,因为你不知道用fs的哪个方法,我也是从fs里试水试了一天,各种百度才搞出来的,特别学过java的 ...
- wepy 小程序云开发
小程序前段时间更新了云开发的功能,刚听到对时候觉得简直是个人开发者对福音,尤其是对我这样对后端不是很懂对前端傻傻,简直不能太方便,就试了下. 体验二维码: 源码:https://github.com/ ...
- how find out what is causing Visual Studio to think each project is out of date
You can find out what is causing Visual Studio to think each project is out of date, and then addres ...
- uva-10382-贪心
题意:对于长为L,宽为W的矩形草地,需要对它进行浇水,总共有n个水龙头,给每个水龙头的浇水半径,和位置.求覆盖整个草地需要的最小水龙头数量. 如图,把浇水的面积转换成矩形,然后就和区间覆盖一样了,直接 ...