Home Java javaTutorial Introduction to the implementation principle of ReentrantLock (code example)

Introduction to the implementation principle of ReentrantLock (code example)

Jan 31, 2019 am 11:14 AM
reentrantlock

This article brings you an introduction to the implementation principles of ReentrantLock (code examples). It has certain reference value. Friends in need can refer to it. I hope it will be helpful to you.

In concurrent programming, in addition to the synchronized keyword, ReentrantLock and ReentrantReadWriteLock in java.util.concurrent.locks in the java concurrency package are also commonly used lock implementations. This article analyzes the principle of reentrant lock from the source code.

Let’s first talk about reentrant locks: After a thread obtains the lock, it can obtain the lock multiple times without blocking itself.

ReentrantLock is implemented based on the abstract class AbstractQueuedSynchronizer (hereinafter referred to as AQS).

Look at the source code:

First of all, it can be seen from the constructor that ReentrantLock has two mechanisms: fair lock and unfair lock.

//默认非公平锁
public ReentrantLock() {
        sync = new NonfairSync();
    }

public ReentrantLock(boolean fair) {
        sync = fair ? new FairSync() : new NonfairSync();
    }
Copy after login

First briefly explain the difference between fair locks and unfair locks, and then analyze the different implementation methods of the two.

Fair lock: Multiple threads are first-come, first-served. Similar to queuing, threads coming later are placed at the end of the queue.

Unfair lock: compete for locks. If it is grabbed, it will be executed. If it is not grabbed, it will be blocked. Wait for the thread that acquired the lock to be released before participating in the competition.

So unfair locks are usually used. Its efficiency is higher than fair lock.

Get lock

Fair lock

final void lock() {
            acquire(1);
        }

public final void acquire(int arg) {
        if (!tryAcquire(arg) &&
            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
            selfInterrupt();
    }
Copy after login

The first step is tryAcquire(arg) try to add Lock, implemented by FairSync, the specific code is as follows:

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;
        }
Copy after login

  • ##Get the current thread

  • Get the state in AQS. If state is 0, it means that no thread has obtained the lock at this time.

  • In the if judgment, you must first determine whether the AQS Node queue is empty. If it's not empty, you'll need to queue. The lock is not acquired at this time.

  • Try to use the CAS algorithm to update state to 1. The update is successful, the lock is acquired, and the thread at this time is set to the exclusive thread exclusiveOwnerThread. Return true.

  • If state is not 0, it means that a thread has already obtained the lock. Therefore, it is necessary to determine whether the thread that obtained the lock (exclusive thread) is the current thread.

  • If yes, it means reentrancy. Increase state by 1. Return true.

  • At the last step, the lock is not obtained. Return false;

Continue with the above steps. If acquisition of the lock fails, first execute addWaiter(Node.EXCLUSIVE) and write the current thread into the queue

private Node addWaiter(Node mode) {
        Node node = new Node(Thread.currentThread(), mode);
        // Try the fast path of enq; backup to full enq on failure
        Node pred = tail;
        if (pred != null) {
            node.prev = pred;
            if (compareAndSetTail(pred, node)) {
                pred.next = node;
                return node;
            }
        }
        enq(node);
        return node;
    }
Copy after login

  • Encapsulate a new node node

  • Determine whether the end of the linked list is empty, if not, write the new node node' to the end

  • 'If the end of the linked list is empty, use enq(node) to write to the end.

After writing to the queue, the acquireQueued() method suspends the current thread.

final boolean acquireQueued(final Node node, int arg) {
        boolean failed = true;
        try {
            boolean interrupted = false;
            for (;;) {
                final Node p = node.predecessor();
                if (p == head && tryAcquire(arg)) {
                    setHead(node);
                    p.next = null; // help GC
                    failed = false;
                    return interrupted;
                }
                if (shouldParkAfterFailedAcquire(p, node) &&
                    parkAndCheckInterrupt())
                    interrupted = true;
            }
        } finally {
            if (failed)
                cancelAcquire(node);
        }
    }
Copy after login

  • In the loop, if the previous node is the head node, try to acquire the lock again. If successful, the loop will end and false will be returned.

  • is not the head node. Based on the waitStatus of the previous node, it is judged whether the current thread needs to be suspended. waitStatus is used to record node status, such as node cancellation, node waiting, etc.

  • If you determine that you need to suspend, use the parkAndCheckInterrupt() method to suspend the thread. Specifically, use LockSupport.park(this) to suspend the thread.

  • If the lock acquisition is successful in the first step here, you can cancel the lock acquisition operation for this node.

Unfair lock

Unfair lock has differences in lock acquisition strategies.

final void lock() {
            if (compareAndSetState(0, 1))
                setExclusiveOwnerThread(Thread.currentThread());
            else
                acquire(1);
        }
 protected final boolean tryAcquire(int acquires) {
            return nonfairTryAcquire(acquires);
        }
Copy after login

  • The unfair lock first directly tries to use the CAS algorithm to update the state and acquire the lock

  • After the update fails, when trying to acquire the lock

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;
        }
Copy after login

Compared with the fair lock, the unfair lock tries to acquire the lock. There is no need to determine whether there are other threads in the queue.

Release lock

The steps for releasing locks are the same for fair locks and unfair locks

public void unlock() {
        sync.release(1);
    }
public final boolean release(int arg) {
        if (tryRelease(arg)) {
            Node h = head;
            if (h != null && h.waitStatus != 0)
                unparkSuccessor(h);
            return true;
        }
        return false;
    }
//更新state
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;
        }
Copy after login

It is worth noting that because it is a reentrant lock, in the tryRelease() method, the state needs to be updated to 0 before the lock is considered to be completely released. After releasing, wake up the suspended thread.

The above is the detailed content of Introduction to the implementation principle of ReentrantLock (code example). For more information, please follow other related articles on the PHP Chinese website!

Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn

Hot AI Tools

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Undress AI Tool

Undress AI Tool

Undress images for free

Clothoff.io

Clothoff.io

AI clothes remover

Video Face Swap

Video Face Swap

Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Article

Roblox: Bubble Gum Simulator Infinity - How To Get And Use Royal Keys
3 weeks ago By 尊渡假赌尊渡假赌尊渡假赌
Nordhold: Fusion System, Explained
3 weeks ago By 尊渡假赌尊渡假赌尊渡假赌

Hot Tools

Notepad++7.3.1

Notepad++7.3.1

Easy-to-use and free code editor

SublimeText3 Chinese version

SublimeText3 Chinese version

Chinese version, very easy to use

Zend Studio 13.0.1

Zend Studio 13.0.1

Powerful PHP integrated development environment

Dreamweaver CS6

Dreamweaver CS6

Visual web development tools

SublimeText3 Mac version

SublimeText3 Mac version

God-level code editing software (SublimeText3)

Hot Topics

Java Tutorial
1664
14
PHP Tutorial
1268
29
C# Tutorial
1248
24
Is the company's security software causing the application to fail to run? How to troubleshoot and solve it? Is the company's security software causing the application to fail to run? How to troubleshoot and solve it? Apr 19, 2025 pm 04:51 PM

Troubleshooting and solutions to the company's security software that causes some applications to not function properly. Many companies will deploy security software in order to ensure internal network security. ...

How do I convert names to numbers to implement sorting and maintain consistency in groups? How do I convert names to numbers to implement sorting and maintain consistency in groups? Apr 19, 2025 pm 11:30 PM

Solutions to convert names to numbers to implement sorting In many application scenarios, users may need to sort in groups, especially in one...

How to simplify field mapping issues in system docking using MapStruct? How to simplify field mapping issues in system docking using MapStruct? Apr 19, 2025 pm 06:21 PM

Field mapping processing in system docking often encounters a difficult problem when performing system docking: how to effectively map the interface fields of system A...

How does IntelliJ IDEA identify the port number of a Spring Boot project without outputting a log? How does IntelliJ IDEA identify the port number of a Spring Boot project without outputting a log? Apr 19, 2025 pm 11:45 PM

Start Spring using IntelliJIDEAUltimate version...

How to elegantly obtain entity class variable names to build database query conditions? How to elegantly obtain entity class variable names to build database query conditions? Apr 19, 2025 pm 11:42 PM

When using MyBatis-Plus or other ORM frameworks for database operations, it is often necessary to construct query conditions based on the attribute name of the entity class. If you manually every time...

How to safely convert Java objects to arrays? How to safely convert Java objects to arrays? Apr 19, 2025 pm 11:33 PM

Conversion of Java Objects and Arrays: In-depth discussion of the risks and correct methods of cast type conversion Many Java beginners will encounter the conversion of an object into an array...

How to use the Redis cache solution to efficiently realize the requirements of product ranking list? How to use the Redis cache solution to efficiently realize the requirements of product ranking list? Apr 19, 2025 pm 11:36 PM

How does the Redis caching solution realize the requirements of product ranking list? During the development process, we often need to deal with the requirements of rankings, such as displaying a...

E-commerce platform SKU and SPU database design: How to take into account both user-defined attributes and attributeless products? E-commerce platform SKU and SPU database design: How to take into account both user-defined attributes and attributeless products? Apr 19, 2025 pm 11:27 PM

Detailed explanation of the design of SKU and SPU tables on e-commerce platforms This article will discuss the database design issues of SKU and SPU in e-commerce platforms, especially how to deal with user-defined sales...

See all articles