Java 显示锁 之 重入锁 ReentrantLock(七)
ReentrantLock 重入锁简介
重入锁 ReentrantLock,顾名思义,就是支持同一个线程对资源的重复加锁。另外,该锁还支持获取锁时的公平与非公平性的选择。
重入锁 ReentrantLock,只支持独占方式的获取操作,因此它只实现了 tryAcquire、tryRelease 和 isHeldExclusively 方法。
ReentrantLock 如何实现锁重入
锁重入是指任意线程在获取到锁之后,能够再次获取该锁而不会被锁所阻塞,该特性的实现需要解决两个问题:
1、线程再次获取锁
需要识别获取锁的线程是否为当期占有锁的线程,如果是,则便获取锁成功
2、锁最终得到释放
同一个线程重复 n 次获得了锁,在第 n 次释放该锁后,其它线程能够获取到该锁。锁的最终释放要求锁对于获取进行计数,计数表示当前锁被重复获取的次数,而锁被释放时,计数自减,当计数等于0时,表示锁已经成功释放
ReentrantLock 是通过自定义同步器来实现所得获取和释放,默认使用非公平性,下面就以非公平性获取锁为例,学习重入锁是如何实现的:
final boolean nonfairTryAcquire(int acquires) {
//当前线程
final Thread current = Thread.currentThread();
//当前同步状态
int c = getState();
//当前同步状态等于0,说明当前线程可以获取同步状态
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;
}
通过判断当前线程是否为获取锁的线程来决定获取操作是否成功,如果是获取锁的线程,则将同步状态值进行累加并返回true,表示获取同步状态成功。
成功获取锁的线程再次获取锁,只是增加了同步状态值,这也就要求在释放同步状态时递减同步状态的值。如下,释放锁的代码:
protected final boolean tryRelease(int releases) {
int c = getState() - releases;
if (Thread.currentThread() != getExclusiveOwnerThread())
throw new IllegalMonitorStateException();
boolean free = false;
if (c == 0) {
free = true;
setExclusiveOwnerThread(null);
}
setState(c);
return free;
}
如果该锁被获取了n次, 那么前( n- 1) 次 tryRelease( int releases) 方法必须返回false,只有同步状态完全释放了,才能返回tru。 该方法将同步状态 是否为 0 作为作为最终释放的条件,当同步状态为0时,将该锁的拥有者线程设置为null,并返回true,表示成功释放。
ReentrantLock 如何实现锁的公平性与非公平性
公平性与否是针对获取锁而言的,如果一个锁时公平的,那么锁的获取顺序就应该服务请求时间的顺序,也就是FIFO。
由上文介绍的非公平获取锁方法 nonfairTryAcquire( int acquires) 可知,只要CAS设置同步状态成功,则表示线程获取了锁,而公平锁则不同,如代码所示:
static final class FairSync extends Sync {
protected final boolean tryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
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;
}
}
该方法与 nonfairTryAcquire( int acquires) 的区别在于多了hasQueuedPredecessors() 方法,即加入了同步队列中当前节点是否有前驱节点的判断,如果该方法返回true,则表示有线程比当前线程更早的请求了锁,因此需要等待前驱线程获取并释放锁之后才能继续获取锁。
Java 显示锁 之 重入锁 ReentrantLock(七)的更多相关文章
- 浅谈Java中的公平锁和非公平锁,可重入锁,自旋锁
公平锁和非公平锁 这里主要体现在ReentrantLock这个类里面了 公平锁.非公平锁的创建方式: //创建一个非公平锁,默认是非公平锁 Lock lock = new ReentrantLock( ...
- java面试-公平锁/非公平锁/可重入锁/递归锁/自旋锁谈谈你的理解
一.公平锁/非公平锁/可重入锁/递归锁/自旋锁谈谈你的理解 公平锁:多个线程按照申请的顺序来获取锁. 非公平锁:多个线程获取锁的先后顺序与申请锁的顺序无关.[ReentrantLock 默认非公平.s ...
- 可重入锁 & 不可重入锁
可重入锁指同一个线程可以再次获得之前已经获得的锁,避免产生死锁. Java中的可重入锁:synchronized 和 java.util.concurrent.locks.ReentrantLock. ...
- 二、多线程基础-乐观锁_悲观锁_重入锁_读写锁_CAS无锁机制_自旋锁
1.10乐观锁_悲观锁_重入锁_读写锁_CAS无锁机制_自旋锁1)乐观锁:就像它的名字一样,对于并发间操作产生的线程安全问题持乐观状态,乐观锁认为竞争不总是会发生,因此它不需要持有锁,将 比较-设置 ...
- redis分布式锁-可重入锁
redis分布式锁-可重入锁 上篇redis实现的分布式锁,有一个问题,它不可重入. 所谓不可重入锁,即若当前线程执行某个方法已经获取了该锁,那么在方法中尝试再次获取锁时,就会获取不到被阻塞. 同一个 ...
- Java多线程系列——深入重入锁ReentrantLock
简述 ReentrantLock 是一个可重入的互斥(/独占)锁,又称为“独占锁”. ReentrantLock通过自定义队列同步器(AQS-AbstractQueuedSychronized,是实现 ...
- java线程的同步控制--重入锁ReentrantLock
我们常用的synchronized关键字是一种最简单的线程同步控制方法,它决定了一个线程是否可以访问临界区资源.同时Object.wait() 和Object.notify()方法起到了线程等待和通知 ...
- Java并发包4--可重入锁ReentrantLock的实现原理
前言 ReentrantLock是JUC提供的可重入锁的实现,用法上几乎等同于Synchronized,但是ReentrantLock在功能的丰富性上要比Synchronized要强大. 一.Reen ...
- Java并发编程-可重入锁
可重入锁,也叫做递归锁,指的是同一线程 外层函数获得锁之后 ,内层递归函数仍可以获取该锁而不受影响.在JAVA环境下 ReentrantLock 和synchronized 都是 可重入锁. publ ...
随机推荐
- java Lesson08总结
package com.xt.java.FirstExciple.oop; public class NokiaPhone { //成员变量 String name="np001" ...
- python现状
自从官方宣布 2020 年 1 月后不再更新维护 Python2,已经有一大批开源软件将其抛弃.今天,抛弃 Python2 的名单上又多了一个重磅软件.Python2 是 Python 官方在 200 ...
- go语言入门(7)面向对象编程
1,概述 对于面向对象编程的支持Go 语言设计得非常简洁而优雅.因为, Go语言并没有沿袭传统面向对象编程中的诸多概念,比如继承(不支持继承,尽管匿名字段的内存布局和行为类似继承,但它并不是继 ...
- python生成式:列表、字典、集合
python的3类生成式: 列表生成式 字典生成式 集合生成式 1.python列表生成式 my_data = [[1, 2, 3], [4, 5, 6], [7, 8, 9]] print(&quo ...
- 【leetcode】296.Best Meeting Point
原题 A group of two or more people wants to meet and minimize the total travel distance. You are given ...
- golang结构体json格式化的时间格式
golang结构体json格式化的时间格式 在我们开发中,经常会解析time.Time 往往前台传过来的时候,是个string 但是我们希望在结构体转成time.Time type Param str ...
- java——多线程—启动线程
继承Thread启动线程 package com.mycom.继承Thread启动线程; /** * * 继承Thread类启动线程的步骤 * 1.定义自定义线程类并继承Thread * 2.重写ru ...
- 牛客小白月赛19 E 「火」烈火燎原 (思维,树)
牛客小白月赛19 E 「火」烈火燎原 (思维,树) 链接:https://ac.nowcoder.com/acm/contest/2272/E来源:牛客网 时间限制:C/C++ 1秒,其他语言2秒 空 ...
- 关于从入 OI 以来学的各种知识点的系统总结
前言 OI 之路差不多快结束了,最近水平也萎得很厉害,这里就开个目录,记录一些需要总结的知识点吧.不定期更,勿催,我还要改模拟赛的题. 目录
- c++中new的知识点
在练习内存池时,发现需要重载new,可是这个重载只是重载了operator new,那么还有哪几种new呢,下面来记录一下 首先记录一个点,在类中重载operator new,默认就是静态成员函数,所 ...