彻底理解Java并发:ReentrantLock锁
创始人
2024-04-02 01:05:26

本篇内容包括:为什么使用 Lock、Lock 锁注意事项、ReentrantLock 和 synchronized 对比、ReentrantLock (加锁、解锁、公平锁与非公平锁、ReentrantLock 如何实现可重入)等内容。

一、Lock 锁

1、为什么使用 Lock

synchronized 线程等待时间过长,获取锁的线程由于要等待IO或者其他原因(比如调用sleep方法)被阻塞了,但是又没有释放锁,其他线程便只能干巴巴地等待,这将极大的影响程序执行效率。

synchronized 操作场景,如果多个线程都只是进行读操作,所以当一个线程在进行读操作时,其他线程只能等待无法进行读操作。

2、注意事项

也就是说 Lock 提供了比 synchronized 更多的功能。但是要注意以下几点

  • Lock 不是 Java 语言内置的,synchronized 是 Java 语言的关键字,因此是内置特性。Lock 是一个类,通过这个类可以实现同步访问;
  • Lock 和 synchronized 有一点非常大的不同,采用 synchronized 不需要用户去手动释放锁,当 synchronized 方法或者 synchronized 代码块执行完之后,系统会自动让线程释放对锁的占用;而 Lock 则必须要用户去手动释放锁,如果没有主动释放锁,就有可能导致出现死锁现象。

3、ReentrantLock 和 synchronized

ReentrantLock 是 java.util.concurrent.locks 包中的一个类,是独占锁,为最后一个执行 lock 操作成功且为释放锁的线程锁拥有

ReentrantLock 是可重入的互斥锁,虽然具有与 synchronized 相同功能,但是会比 synchronized 更加灵活

ReentrantLock 使用代码实现了和 synchronized 一样的语义,包括可重入,保证内存可见性和解决竞态条件问题等。与 synchronized 相较之下:

  • 便利性:Synchronized 用法更简洁,由编译器去保证锁的加锁和释放; ReenTrantLock 需要手动加锁和释放锁,为了避免忘记手工释放锁造成死锁,所以最好在 finally 中声明释放锁。
  • 锁的细粒度和灵活度:ReenTrantLock 优于 Synchronized

此外,以下特点是 ReenTrantLock 独有:

  • ReenTrantLock 可以指定是公平锁还是非公平锁; synchronized 只能是非公平锁。
  • ReenTrantLock 提供了一个 Condition 类,用来实现唤醒特定的线程; synchronized 要么随机唤醒一个线程要么唤醒全部线程。
  • ReenTrantLock 提供了一种能够中断等待锁的线程的机制。

二、ReentrantLock

ReentrantLock,它是一个“可重入”锁。

什么是“可重入”?简单地讲就是:“同一个线程对于已经获得到的锁,可以多次继续申请到该锁的使用权”

正经地讲就是:假如访问一个资源A需要获得其锁lock,如果之前没有其他线程获取该锁,那么当前线程就获锁成功,此时该线程对该锁后续所有“请求”都将立即得到“获锁成功”的返回,即同一个线程可以多次成功的获取到之前获得的锁。“可重入”可以解释成“同一个线程可多次获取”。

大致的特性

  • 基本锁的特性:加锁、解锁

  • ReentrantLock的补充特性:可重入、公平、非公平

1、加锁、解锁

这两个方法在源码中加锁方法即为lock(),解锁方法即为unLock() ,实现如下:

//加锁
public void lock() {sync.lock();
}//释放锁
public void unlock() {sync.release(1);
}

从上述可以知道这两个方法实际上是操作了一个叫做 sync 的对象,调用该对象的 lock 和 release 操作来实现,sync 是什么东西?ReentrantLock 类的源码片段:

public class ReentrantLock implements Lock, java.io.Serializable {private static final long serialVersionUID = 7373984872572414699L;private final Sync sync;
}

ReentrantLock 实现了 Lock 接口,操作其成员变量 sync 这个 AQS 的子类,来完成锁的相关功能。而 sync 这个成员变量有2种形态:NonfairSync 和 FairSync,在源码中,只有在2个构造函数的地方对sync对象做了初始化

/** 所有锁操作都是基于这个字段 */
private final Sync sync;
/*** 通过该构造函数创建额ReentrantLock是一个非公平锁*/
public ReentrantLock() {sync = new NonfairSync();
}
/*** 如果入参为true,则创建公平的ReentrantLock;* 否则,创建非公平锁*/
public ReentrantLock(boolean fair) {sync = fair ? new FairSync() : new NonfairSync();
}

这两个对象(NonfairSync和NonfairSync)也是 ReentrantLock 的内部类,FairSync 和 NonFairSync 在类结构上完全一样且均继承于 Sync。

img

ReentrantLock的构造函数中,默认的无参构造函数将会把Sync对象创建为NonfairSync对象,这是一个“非公平锁”;而另一个构造函数ReentrantLock(boolean fair)传入参数为true时将会把Sync对象创建为“公平锁”FairSync

2、公平锁与非公平锁

img

FairSync 在 tryAquire 方法中,当判断到锁状态字段state == 0 时,不会立马将当前线程设置为该锁的占用线程,而是去判断是在此线程之前是否有其他线程在等待这个锁(执行hasQueuedPredecessors() 方法),如果是的话,则该线程会加入到等待队列中,进行排队(FIFO,先进先出的排队形式)。这也就是为什么 FairSync 可以让线程之间公平获得该锁。

NoFairSync的tryAquire 方法中,没有判断是否有在此之前的排队线程,而是直接进行获锁操作,因此多个线程之间同时争用一把锁的时候,谁先获取到就变得随机了,很有可能线程A比线程B更早等待这把锁,但是B却获取到了锁,A继续等待(这种现象叫做:线程饥饿)

到此,我们已经大致理解了 ReentrantLock 是如何做到不同线程如何“公平”和“非公平”获锁。

3、如何实现可重入

我们有提到加锁操作会对 state 字段进行 +1 操作

这里需要注意到 AQS 中很多内部变量的修饰符都是采用的 volital,然后配合 CAS 操作来保证 AQS 本身的线程安全(因为 AQS 自己线程安全,基于它的衍生类才能更好地保证线程安全),这里的 state 字段就是 AQS 类中的一个用 volitale 修饰的 int 变量

state 字段初始化时,值为 0。表示目前没有任何线程持有该锁。当一个线程每次获得该锁时,值就会在原来的基础上加 1,多次获锁就会多次加 1(指同一个线程),这里就是可重入。因为可以同一个线程多次获锁,只是对这个字段的值在原来基础上加1; 相反 unlock 操作也就是解锁操作,实际是是调用 AQS 的 release 操作,而每执行一次这个操作,就会对 state 字段在原来的基础上减1,当 state==0 的 时候就表示当前线程已经完全释放了该锁。

相关内容

热门资讯

长白山自助游攻略 吉林长白山游... 昨天介绍了西坡的景点详细请看链接:一个人的旅行,据说能看到长白山天池全凭运气,您的运气如何?今日介绍...
埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
应用未安装解决办法 平板应用未... ---IT小技术,每天Get一个小技能!一、前言描述苹果IPad2居然不能安装怎么办?与此IPad不...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
脚上的穴位图 脚面经络图对应的... 人体穴位作用图解大全更清晰直观的标注了各个人体穴位的作用,包括头部穴位图、胸部穴位图、背部穴位图、胳...
demo什么意思 demo版本... 618快到了,各位的小金库大概也在准备开闸放水了吧。没有小金库的,也该向老婆撒娇卖萌服个软了,一切只...
埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
长白山自助游攻略 吉林长白山游... 昨天介绍了西坡的景点详细请看链接:一个人的旅行,据说能看到长白山天池全凭运气,您的运气如何?今日介绍...
世界上最漂亮的人 世界上最漂亮... 此前在某网上,选出了全球265万颜值姣好的女性。从这些数量庞大的女性群体中,人们投票选出了心目中最美...
应用未安装解决办法 平板应用未... ---IT小技术,每天Get一个小技能!一、前言描述苹果IPad2居然不能安装怎么办?与此IPad不...
脚上的穴位图 脚面经络图对应的... 人体穴位作用图解大全更清晰直观的标注了各个人体穴位的作用,包括头部穴位图、胸部穴位图、背部穴位图、胳...
猫咪吃了塑料袋怎么办 猫咪误食... 你知道吗?塑料袋放久了会长猫哦!要说猫咪对塑料袋的喜爱程度完完全全可以媲美纸箱家里只要一有塑料袋的响...
demo什么意思 demo版本... 618快到了,各位的小金库大概也在准备开闸放水了吧。没有小金库的,也该向老婆撒娇卖萌服个软了,一切只...
埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...