* A reentrant mutual exclusion {@link Lock} with the same basic
* behavior and semantics as the implicit monitor lock accessed using
* {@code synchronized} methods and statements, but with extended
* capabilities.

一个可重入的互斥锁,它与使用synchronized的方法和语句来进行隐式锁访问的方式具有相同的基本行为和语义,但是同时具有一些扩展功能。

* <p>The constructor for this class accepts an optional
* <em>fairness</em> parameter. When set {@code true}, under
* contention, locks favor granting access to the longest-waiting
* thread. Otherwise this lock does not guarantee any particular
* access order. Programs using fair locks accessed by many threads
* may display lower overall throughput (i.e., are slower; often much
* slower) than those using the default setting, but have smaller
* variances in times to obtain locks and guarantee lack of
* starvation.

ReentrantLock构造方法接收一个可选的公平参数。当设置为true时,它是公平锁,这时锁会将访问权授予等待时间最长的线程。否则该锁将无法保证线程获取锁的访问顺序。公平锁与非公平锁相比,使用公平锁的程序会有较低的吞吐量,但使用公平锁能有效减少线程饥饿的发生。

使用建议:一般推荐的使用方式就是 lock()后紧跟try块,例如:

 class X {
private final ReentrantLock lock = new ReentrantLock();
// ... public void m() {
lock.lock(); // block until condition holds
try {
// ... method body
} finally {
lock.unlock()
}
}
}}

一、源码解析

private final Sync sync;

/**
* Base of synchronization control for this lock. Subclassed
* into fair and nonfair versions below. Uses AQS state to
* represent the number of holds on the lock.
*/
abstract static class Sync extends AbstractQueuedSynchronizer /**
* Sync object for non-fair locks
*/
static final class NonfairSync extends Sync /**
* Sync object for fair locks
*/
static final class FairSync extends Sync

以上为ReentrantLock提供的3个静态内部类,其中Sync类继承自AbstractQueuedSynchronizer(抽象队列同步器),而NonfairSync和FairSync为Sync类的两个实现,分别应用于非公平锁和公平锁的场景,而公平锁和非公平锁在释放锁的情况都是一样的,只是在获取锁时,公平锁会让等待最久的线程优先获取到锁,而非公平锁在获取锁时各线程机会均等,这样也就导致会出现饥饿现象产生.

static final class FairSync extends Sync
final void lock() {acquire(1);}
static final class NonfairSync extends Sync
{
final void lock() {
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);
}
}

以上为公平锁和非公平锁调用lock()的源码,其中的compareAndSetState,setExclusiveOwnerThread和acquire 均来自AQS中,有次可以看出非公平锁在lock时就会去尝试1次去获取锁,获取到了就返回,如果获取不到,则跟公平锁一样,调用acquire(arg)再次尝试获取锁,说白了,非公平锁比公平锁多1次抢占锁的动作。而在抢占动作中,非公平锁是直接尝试抢占,而公平锁会先判断是否位于头结点来决定是否抢占。

非公平锁获取锁源码

final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();
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;
}

公平锁获取锁源码

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;
}

二、使用场景

场景1 防止重复执行

ReentrantLock lock = new ReentrantLock();

if(lock.tryLock()){//如果已经被lock,则直接放回false,不会等待,达到忽略的效果
try
{ }finally {
lock.unlock();
}
}

场景2 串行执行(同步执行,类似synchronized)

try
{
lock.lock(); }finally {
lock.unlock();
}

场景3 超时等待

try{
if(lock.tryLock(5, TimeUnit.SECONDS)){
try
{ }finally {
lock.unlock();
}
}
}catch (InterruptedException ex){
ex.printStackTrace();
}

场景4 响应中断

try {
lock.lockInterruptibly(); } catch (InterruptedException ex) {
ex.printStackTrace();
} finally {
lock.unlock();
}

J.U.C之ReentrantLock 可重入锁的更多相关文章

  1. ReenTrantLock可重入锁(和synchronized的区别)总结

    ReenTrantLock可重入锁(和synchronized的区别)总结 可重入性: 从名字上理解,ReenTrantLock的字面意思就是再进入的锁,其实synchronized关键字所使用的锁也 ...

  2. ReentrantLock可重入锁的理解和源码简单分析

    import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.ReentrantLock; /** * @author ...

  3. ReenTrantLock可重入锁和synchronized的区别

    ReenTrantLock可重入锁和synchronized的区别 可重入性: 从名字上理解,ReenTrantLock的字面意思就是再进入的锁,其实synchronized关键字所使用的锁也是可重入 ...

  4. JUC 一 ReentrantLock 可重入锁

    java.util.concurrent.locks ReentrantLock即可重入锁,实现了Lock和Serializable接口 ReentrantLock和synchronized都是可重入 ...

  5. java ReentrantLock可重入锁功能

    1.可重入锁是可以中断的,如果发生了死锁,可以中断程序 //如下程序出现死锁,不去kill jvm无法解决死锁 public class Uninterruptible { public static ...

  6. ReentrantLock——可重入锁的实现原理

    一. 概述 本文首先介绍Lock接口.ReentrantLock的类层次结构以及锁功能模板类AbstractQueuedSynchronizer的简单原理,然后通过分析ReentrantLock的lo ...

  7. 40 多线程(十二)——ReentrantLock 可重入锁

    我们使用的synchronized加的锁是可以延续使用的,如下: public void test() { //第一次获得锁 synchronized(this) { while(true) { // ...

  8. ReentrantLock可重入锁、公平锁非公平锁区别与实现原理

    ReentrantLock是lock接口的一个实现类,里面实现了可重入锁和公平锁非公平锁 ReentrantLock公平锁和不公平锁实现原理 公平锁会获取锁时会判断阻塞队列里是否有线程再等待,若有获取 ...

  9. ReentrantLock可重入锁——源码详解

    开始这篇博客之前,博主默认大家都是看过AQS源码的~什么居然没看过猛戳下方 全网最详细的AbstractQueuedSynchronizer(AQS)源码剖析(一)AQS基础 全网最详细的Abstra ...

随机推荐

  1. linux命令查询网站

    http://linux.51yip.com/ http://man.linuxde.net/ Linux命令查询手册Linux终端下 esc + . 可以获取上次文件名

  2. 基于函数的I/O操作(头文件stdio.h)

    基于函数库的I/O是C语言标准库的功能,基于系统级I/O函数实现. 系统级I/O函数对文件的标识是文件描述符,C语言标准库中对文件的标识是指向FILE结构的指针.在头文件cstdio或stdio.h中 ...

  3. [PyTorch 学习笔记] 2.1 DataLoader 与 DataSet

    thumbnail: https://image.zhangxiann.com/jeison-higuita-W19AQY42rUk-unsplash.jpg toc: true date: 2020 ...

  4. Spring是如何解决循环依赖的

    前言 在面试的时候这两年有一个非常高频的关于spring的问题,那就是spring是如何解决循环依赖的.这个问题听着就是轻描淡写的一句话,其实考察的内容还是非常多的,主要还是考察的应聘者有没有研究过s ...

  5. quartz表(11张)

    /* Navicat Premium Data Transfer Source Server : 本地连接 Source Server Type : MySQL Source Server Versi ...

  6. Apache Tika实战

    Apache Tika实战 Tika 简介 Apache Tika 是一个内容分析工具包,可以检测上千种文件类型,并提取它们的元数据和文本.tika在设计上十分精巧,单一的接口使它易于使用,在搜索引擎 ...

  7. python爬取酷我音乐(收费也可)

    第一次创作,请多指教 环境:Python3.8,开发工具:Pycharm 很多人学习python,不知道从何学起.很多人学习python,掌握了基本语法过后,不知道在哪里寻找案例上手.很多已经做案例的 ...

  8. Ellxir

    API: elixir https://hexdocs.pm/elixir/Module.html#content API: erlang http://www.cnerlang.com/api.ht ...

  9. 绝世好题(线性dp)

    给定一个长度为n的数列ai,求ai的子序列bi的最长长度,满足bi&bi-1!=0(2<=i<=len).   Input 输入文件共2行. 第一行包括一个整数n. 第二行包括n个 ...

  10. CentOS 7上更改MySQL数据库存储目录浅析

      个人之前总结过两篇文章"MySQL更改数据库数据存储目录"和"Ubuntu上更改MySQL数据库数据存储目录",都是在工作中遇到相关案例后的一个简单总结.当 ...