当前位置:网站首页>Reentrantlock source code analysis
Reentrantlock source code analysis
2022-06-12 11:29:00 【JobsTribe】
Preface
Java Language directly provides synchronized Keyword is used to lock , But this kind of lock is very heavy , Second, we must wait all the time when we get it , There's no extra trial mechanism .
java.util.concurrent.locks Provided by the package ReentrantLock Used in substitution synchronized Lock , Let's take a look at the traditional synchronized Code :
public class Counter {
private int count;
public void add(int n) {
synchronized(this) {
count += n;
}
}
}
ReentrantLock Use samples .
public class Counter {
private final Lock lock = new ReentrantLock();
private int count;
public void add(int n) {
lock.lock();
try {
count += n;
} finally {
lock.unlock();
}
}
}
Constructors
ReentrantLock Default is unfair lock .
If new ReentrantLock(true), Fair lock , Otherwise it's unfair lock .
/**
* Default is unfair lock
*/
public ReentrantLock() {
sync = new NonfairSync();
}
/**
* see boolean Value ,true Lock for fairness ,false Lock for unfairness .
*/
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}
Sync
Used here Sync Is a synchronizer that provides all the implementation mechanisms , Is an abstract class , Inherit AbstractQueuedSynchronizer( namely AQS).
private final Sync sync;
/**
* Synchronization control basis of this lock . The following is divided into fair and unfair versions . Use AQS State to indicate the number of times the lock is held
*/
abstract static class Sync extends AbstractQueuedSynchronizer {
private static final long serialVersionUID = -5179523762034025860L;
/**
* abstract lock
*/
abstract void lock();
/**
* Execution is not fair tryLock.tryAcquire Implemented in subclass , But both need non empty trylock Method
*/
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();
// Get lock status , It uses AQS volatile state state
int c = getState();
if (c == 0) {
// If the state is 0, Indicates that there is no thread lock . Then use CAS Get the lock
if (compareAndSetState(0, acquires)) {
// To be successful , Set the thread holding the current lock as the current thread
setExclusiveOwnerThread(current);
return true;
}
}
// If the current thread holds a lock , This means re-entry lock
else if (current == getExclusiveOwnerThread()) {
// The modification status is the number of times the lock is acquired
int nextc = c + acquires;
if (nextc < 0) // overflow
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
// Try to release the lock
protected final boolean tryRelease(int releases) {
int c = getState() - releases;
// The current thread does not hold a lock , Throw the wrong
if (Thread.currentThread() != getExclusiveOwnerThread())
throw new IllegalMonitorStateException();
// Whether the flag is completely released
boolean free = false;
//c by 0, It indicates that the status is fully released
if (c == 0) {
// Change logo to true, And change the thread holding the lock to null
free = true;
setExclusiveOwnerThread(null);
}
// Reset the state of the lock , And return to the state of releasing the lock
setState(c);
return free;
}
// Determine whether the current thread holds the lock
protected final boolean isHeldExclusively() {
// While we must in general read state before owner,
// we don't need to do so to check if current thread is owner
return getExclusiveOwnerThread() == Thread.currentThread();
}
// Get a new one Condition object
final ConditionObject newCondition() {
return new ConditionObject();
}
// Get the thread holding the current lock , When it comes to 0 It means that there is no thread , Otherwise, get the current thread that holds the lock
final Thread getOwner() {
return getState() == 0 ? null : getExclusiveOwnerThread();
}
// Gets the number of times the current lock is held
final int getHoldCount() {
return isHeldExclusively() ? getState() : 0;
}
// Determine whether a thread holds the current lock
final boolean isLocked() {
return getState() != 0;
}
/**
* Reconstitutes the instance from a stream (that is, deserializes it).
*/
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
s.defaultReadObject();
setState(0); // reset to unlocked state
}
}
FairSync: Fair lock
Inheritance relationships

Source code analysis
/**
* Sync object for fair locks
*/
static final class FairSync extends Sync {
private static final long serialVersionUID = -3000897897090466540L;
final void lock() {
acquire(1);
}
// Fair lock version tryAcquire
protected final boolean tryAcquire(int acquires) {
final Thread current = Thread.currentThread();
// Get lock status
int c = getState();
// The current lock status is 0, That is, no thread holds
if (c == 0) {
//hasQueuedPredecessors: Determine whether there are other threads ahead of the current thread .
// If the current thread does not have , also CAS success , Then directly set the thread holding the lock as the current thread
if (!hasQueuedPredecessors() &&
compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
// If the current thread holds a lock , This means re-entry lock
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < 0)
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
}
among hasQueuedPredecessors() function , Method from AQS. Used to determine whether other threads are ahead of the current thread .
public final boolean hasQueuedPredecessors() {
// The correctness of this depends on head being initialized
// before tail and on head.next being accurate if the current
// thread is first in queue.
Node t = tail; // Read fields in reverse initialization order
Node h = head;
Node s;
return h != t &&((s = h.next) == null || s.thread != Thread.currentThread());
}
NonfairSync: Not fair lock
Inheritance relationships 
The source code parsing
/**
* Sync object for non-fair locks
*/
static final class NonfairSync extends Sync {
private static final long serialVersionUID = 7316153563782823691L;
// call lock When the method is used , Direct processing
final void lock() {
// Just try to get the lock , To be successful , Then directly set the thread holding the lock as the current thread
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);
}
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
}
acquire() Methods come from the parent class AQS in , The first is to call tryAcquire Method attempts to acquire the lock , If it fails, call addWaiter Method wraps a thread as Node. Then spin CAS The team , And then acquireQueued Method to complete thread blocking .
public final void acquire(int arg) {
if (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
The difference between fair lock and unfair lock
We can see from the source code analysis that , There are several differences :
| Lock type | efficiency | Threads execute | The implementation of |
|---|---|---|---|
| Fair lock | Relatively inefficient , Because every time I have to ask | Sunshine , Each thread has a chance to execute | After the thread enters , First, check whether the queue is empty , If it is empty, it will be locked directly , If it is not empty, it will be queued automatically |
| Not fair lock | Efficient , The lock status can be , It can be locked directly | Thread starve , Some threads may not execute | After the thread enters , Not in order , Will try to scramble for lock first , If it cannot be obtained, it shall be handled in the way of fair lock |
Reentrant lock
A reentry lock is if the thread has acquired the lock , The lock will be acquired again without being blocked by the lock .
The lock acquisition and release process is as follows :
Thread gets lock again . The lock needs to identify whether the thread acquiring the lock is the thread occupying the lock , If so, success again .
The final release of the lock . Threads repeat n Got the lock for the first time , Then in the first n After releasing the lock for the first time , Other threads can acquire the lock . The final release of the lock requires the lock to count the acquisitions , The count indicates the number of times the current lock has been repeatedly acquired , And when the lock is released , The count subtracts itself , When the counter is equal to 0 Indicates that the lock has been successfully released .
边栏推荐
- 【clickhouse专栏】基础数据类型说明
- 十折交叉验证代码中的问题
- When you have a server
- SharDingJDBC-5.1.0按月水平分表+读写分离,自动创表、自动刷新节点表
- FormatConversionTool.exe
- [Blue Bridge Cup SCM 11th National race]
- Pessimistic lock and optimistic lock of MySQL
- Clickhouse column basic data type description
- AcWing 131. The largest rectangle in the histogram (monotone stack classic application template)
- 进程的创建和回收
猜你喜欢

Clickhouse column basic data type description

The reason why scanf return value is ignored and its solution

【藍橋杯單片機 國賽 第十一届】

redis 總結

Clj3-100alh30 residual current relay

k52.第一章 基于kubeadm安装kubernetes v1.22 -- 集群部署

多普勒效应的基本原理

M-arch (fanwai 12) gd32l233 evaluation -cau encryption and decryption (tease Xiaobian)

Clickhouse column basic data type description

B+ 树的简单认识
随机推荐
^33变量提升和函数提升面试题
InfoQ 极客传媒 15 周年庆征文|position:fixed 虚拟按键触发后无法生效问题分析及解决方案探究
如何查看glibc版本
Thinking about the cooperation process of Network Library -- Some Thoughts on reading brpc
^34作用域面试题
当自己有台服务器之后
^33 variable promotion and function promotion interview questions
logrotate日志轮转方式create和copytruncate原理
AI - face
M-arch (fanwai 12) gd32l233 evaluation -cau encryption and decryption (tease Xiaobian)
Unity connect to Microsoft SQLSERVER database
无限生长,我们都将奔赴未来 | InfoQ中国成立15周年
CLJ3-100ALH30剩余电流继电器
The reason why scanf return value is ignored and its solution
Flex layout
Unlimited growth, we will all go to the future | the 15th anniversary of the founding of InfoQ China
Mysql45 lecture 01 | infrastructure: how is an SQL query executed?
LVS health state detection based on application layer
【蓝桥杯单片机 国赛 第十一届】
Selenium uses proxy IP