欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

ReentrantLock详解

程序员文章站 2022-03-26 10:23:45
ReentrantLock概述 ReentrantLock是Lock接口的实现类,可以手动的对某一段进行加锁。ReentrantLock可重入锁,具有可重入性,并且支持可中断锁。其内部对锁的控制有两种实现,一种为公平锁,另一种为非公平锁。ReentrantLock的实现原理为volatile+CAS ......

reentrantlock概述

reentrantlock是lock接口的实现类,可以手动的对某一段进行加锁。reentrantlock可重入锁,具有可重入性,并且支持可中断锁。其内部对锁的控制有两种实现,一种为公平锁,另一种为非公平锁。reentrantlock的实现原理为volatile+cas

reentrantlock可重入性

reentrantlock具有可重入性,可重入性是指当一个线程拥有一个方法的锁以后,是否还可以进入该方法,一般这种情况出现在递归中。reentrantlock的可重入性是基于thread.currentthread()实现的,是线程粒度的,也就是说当前线程获得一个锁以后,当前线程的所有方法都可以获得这个锁。reentrant依赖的锁只有两种实现类,nonfairsyncfairsync,但是它们获取锁的方式大同小异。一下是公平锁的获取实现。reentrantlock.fairsync.tryacquire

 1 protected final boolean tryacquire(int acquires) {
 2             final thread current = thread.currentthread();
 3             int c = getstate();
 4             //每一次加锁state+1
 5             if (c == 0) {
 6                 if (!hasqueuedpredecessors() &&
 7                     compareandsetstate(0, acquires)) {
 8                     setexclusiveownerthread(current);
 9                     return true;
10                   //尝试获取锁成功
11                 }
12             }
13             //是当前线程直接取到到锁,实现锁的可重入
14             else if (current == getexclusiveownerthread()) {
15                 int nextc = c + acquires;
16                 if (nextc < 0)
17                     throw new error("maximum lock count exceeded");
18                 setstate(nextc);
19                 return true;
20             }
21             return false;
22         }
23     }    

reentrantlock锁的实现分析

reentrantlock有两种锁的实现,fairsyncnonfairsync,对于这两种锁,他们获取锁的方式都大同小异reentrantlock$sync#acquire

1    public final void acquire(int arg) {
2         //通过tryacquire去尝试获取锁,公平锁和非公平锁有不同的实现
3         if (!tryacquire(arg) &&
4         //如果没有获取到,就将该线程加入等待队列,然后循环尝试获取该锁
5             acquirequeued(addwaiter(node.exclusive), arg))
6         //如果尝试获取锁的次数达到一定次数,就会触发中断,中断该线程,并释放锁
7             selfinterrupt();
8     }

tryacquire():尝试获取锁;

addwaiter():将线程加入等待队列

acquirequeued():在多次循环中尝试获取到锁或者将当前线程堵塞

selfinterrupt():如果多次未获取成功,将中断该线程(避免死锁)

 

公平锁(fairsync)

公平锁内部维护了一个等待获取该锁的线程的队列,会按照队列顺序给每个线程锁。每当抢占锁的时候,就会判断是否有等待队列,如果有等待队列,就从等待队列的头开始分配锁

ReentrantLock详解
 1         protected final boolean tryacquire(int acquires) {
 2             //取得当前请求锁的线程
 3             final thread current = thread.currentthread();
 4            //取得stage,每一次加锁,stage都会+1,如果stage是0,就说明,没有人使用该锁
 5             int c = getstate();
 6             if (c == 0) {
 7                 //如果没有等待队列,并且cas通过,就将当前线程就抢到了锁
 8                 if (!hasqueuedpredecessors() &&
 9                     compareandsetstate(0, acquires)) {
10                     setexclusiveownerthread(current);
11                     return true;
12                 }
13             }
14             //如果锁没有释放,就判断当前线程是否是该锁的拥有者,如果是,可以直接使用该改,并stage+1
15             else if (current == getexclusiveownerthread()) {
16                 int nextc = c + acquires;
17                 if (nextc < 0)
18                     throw new error("maximum lock count exceeded");
19                 setstate(nextc);
20                 return true;
21             }
22             //如果没有抢到锁,就返回false
23             return false;
24         }
view code

非公平锁(nonfairsync)

非公平锁在抢占锁时,会进行随机抢占,后抢占的线程往往抢占到的几率比较大。

1 if (c == 0) {
2                 //非公平锁仅仅是使用cas,并不会去查看队列(也没有队列)
3                 if (compareandsetstate(0, acquires)) {
4                     setexclusiveownerthread(current);
5                     return true;
6                 }
7             }

reentrantlock的内存可见性

reentrantlock保证内存可见性,作用和synchronized一样,但是要比synchronized更加灵活,方便,reentrantlock可以和condition联合使用