首页 > 其他分享 >ReentrantLock重入锁

ReentrantLock重入锁

时间:2024-03-27 15:47:16浏览次数:21  
标签:重入 return ReentrantLock sync boolean 线程 public

​一,重入锁定义
重入锁,顾名思义,就是支持重新进入的锁,表示这个锁能够支持一个线程对资源重复加锁。如果一个线程已经拿到了锁,那么他需要再次获取锁的时候不会被该锁阻塞。

举个例子,

public synchronized void test(){
    do something...
    test2();
}
public synchronized void test2(){
    do something;
}

test和test2都是同步方法,在执行之前都需要上锁,执行test获取到了锁,test里面调用test2,如果是重入锁,锁识别到获取锁的线程就是当前线程,那么直接进入。如果锁不支持重入,那么显然执行会阻塞在test2()这个位置。

当然,synchronized和ReentrantLock都是重入锁,均支持重新进入。

二,重入锁和非重入锁实现上的区别
上面算是理论,那么具体实现上如何支撑锁的重入性呢?

在队列同步器章节给出了Mutex锁的实现,这个Mutex就是一个非重入锁。

下面是他的代码逻辑,

import java.util.concurrent.locks.AbstractQueuedSynchronizer;

class Mutex implements Lock {
    // 静态内部类,自定义同步器
    private static class Sync extends AbstractQueuedSynchronizer {
        // 是否处于占用状态
        protected boolean isHeldExclusively() {
            return getState() == 1;
        }

        // 当状态为0的时候获取锁
        public boolean tryAcquire(int acquires) {
            if (compareAndSetState(0, 1)) {
                setExclusiveOwnerThread(Thread.currentThread());
                return true;
            }
            return false;
        }

        // 释放锁,将状态设置为0
        protected boolean tryRelease(int releases) {
            if (getState() == 0) throw new
                    IllegalMonitorStateException();
            setExclusiveOwnerThread(null);
            setState(0);
            return true;
        }

        // 返回一个Condition,每个condition都包含了一个condition队列
        Condition newCondition() {
            return new ConditionObject();
        }
    }

    // 仅需要将操作代理到Sync上即可
    private final Sync sync = new Sync();

    public void lock() {
        sync.acquire(1);
    }

    public boolean tryLock() {
        return sync.tryAcquire(1);
    }

    public void unlock() {
        sync.release(1);
    }

    public Condition newCondition() {
        return sync.newCondition();
    }

    public boolean isLocked() {
        return sync.isHeldExclusively();
    }

    public boolean hasQueuedThreads() {
        return sync.hasQueuedThreads();
    }

    public void lockInterruptibly() throws InterruptedException {
        sync.acquireInterruptibly(1);
    }

    public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException {
        return sync.tryAcquireNanos(1, unit.toNanos(timeout));
    }
}

lock方法实际上是去调用同步器的模板方法acquire(int args),而acquire方法又会调用重写的tryAcquire(int args)方法。在Mutex重写的tryAcquire逻辑中,直接尝试用CAS获取锁,成功返回true,失败返回false。

它并没有一个判断同步状态的逻辑,假设当前线程已经是持有锁的线程,重入的时候CAS失败线程就阻塞在了这里,所以Mutex不支持锁的重入。

对比ReentrantLock的逻辑,

    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)
                throw new Error("Maximum lock count exceeded");
            setState(nextc);
            return true;
        }
        return false;
    }

而ReentrantLock的实现,是在上面基础上增加了再次获取同步状态的处理逻辑,即通过判断当前线程是否为持有锁的线程来决定获取操作是否成功,如果不是再去CAS,如果是直接将同步状态增加,相当于上锁次数+1。

既然多次上锁,那么在解锁的时候肯定也需要多次解锁,所以在tryRelease的实现上也会和Mutex不同,

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

假设已经上了n次锁(也就是锁重入了n次),那么前(n-1)次tryRelease必须返回false,只有n次解锁,同步状态完全释放了,才能说我这个锁释放成功了。

而在Mutex的tryRelease逻辑里,只需要设置同步状态是0,直接释放锁即可。

三,synchronized和ReentrantLock
这两个都支持锁的重入,只不过synchronized是隐式的获取/释放锁,隐式地重进入。而ReentrantLock的lock()和unlock()都是我们手写的,在调用lock()方法时,已经获取到锁的线程,能够再次调用lock()方法获取锁而不被阻塞。

均参考整理自《Java 并发编程的艺术》

标签:重入,return,ReentrantLock,sync,boolean,线程,public
From: https://www.cnblogs.com/chengyiyuki/p/18099445

相关文章

  • ReentrantLock 使用
    ReentrantLock介绍ReentrantLock是Java中的一个可重入锁,它提供了与synchronized关键字类似的功能,但相比synchronized,ReentrantLock提供了更多的灵活性和功能。定义:ReentrantLock是一个可重入且独占式的锁,它具有与使用synchronized监视器锁相同的基本行为和语义,但与......
  • 多线程系列(九) -ReentrantLock常用方法详解
    一、简介在上一篇文章中,我们介绍了ReentrantLock类的一些基本用法,今天我们重点来介绍一下ReentrantLock其它的常用方法,以便对ReentrantLock类的使用有更深入的理解。二、常用方法介绍2.1、构造方法ReentrantLock类有两个构造方法,核心源码内容如下:/***默认创建非公平锁*/......
  • 多线程系列(八) -ReentrantLock基本用法介绍
    一、简介在之前的线程系列文章中,我们介绍到了使用synchronized关键字可以实现线程同步安全的效果,以及采用wait()、notify()和notifyAll()方法,可以实现多个线程之间的通信协调,基本可以满足并发编程的需求。但是采用synchronized进行加锁,这种锁一般都比较重,里面的实现机制也非常复......
  • 高并发时为什么推荐ReentrantLock而不是synchronized
    目录1、最初的synchronized2、synchronized的优化3、但是,JAVA的最终答案JDK21LTS来了1、最初的synchronized它默认对临界资源添加重量级锁,即使可能并不存在竞争,只要走到临界区通通给你加锁。现在来回答问题:1)如果是低于JDK1.5,抱歉你没得选,只能先将就着用synchronize......
  • synchronized和ReentrantLock有什么区别
    `synchronized`和`ReentrantLock`都是Java中用于实现同步的机制,但它们之间有一些区别:1.**可重入性**:  -`synchronized`是Java语言内置的关键字,具有可重入性,同一个线程可以多次获取同一个锁而不会造成死锁。  -`ReentrantLock`是`java.util.concurrent.locks`包下的类,也具......
  • ReentrantLock源码分析、LockSuppor、ReentrantReadWriteLock、锁优化的方法
    ReentrantLock类图我们看一下重入锁ReentrantLock类关系图,它是实现了Lock接口的类。NonfairSync和FairSync都继承自抽象类Sync,在ReentrantLock中有非公平锁NonfairSync和公平锁FairSync的实现。在重入锁ReentrantLock类关系图中,我们可以看到NonfairSync和FairSync都继承自抽象......
  • ReentrantLock源码分析、LockSuppor、ReentrantReadWriteLock、锁优化的方法
    ReentrantLock类图我们看一下重入锁ReentrantLock类关系图,它是实现了Lock接口的类。NonfairSync和FairSync都继承自抽象类Sync,在ReentrantLock中有非公平锁NonfairSync和公平锁FairSync的实现。在重入锁ReentrantLock类关系图中,我们可以看到NonfairSync和FairSync都继承自抽象......
  • 可重入锁的含义及解决的问题
    可重入锁顾名思义可以重复利用的锁,但不是任何方法都能重复使用,而是最初占有锁的方法调用的方法,即是调用方法与被调方法可以同时占用同一把锁。下面从三个角度来说明:1.被调方法没有加锁publicclassLockTest{privatestaticfinalObjectobj=newObject();publicv......
  • # ReentrantLock源码阅读
    ReentrantLock源码阅读目录ReentrantLock源码阅读简介例子代码分析Sync.tryLockSync.initialTryLockSync.lockSync.tryReleaseNonFairSync.initialTryLockNonFairSync.tryAcquireFairSync.initialTryLockFairSync.tryAcquire参考链接本人的源码阅读主要聚焦于类的使用场景,一般只......
  • 可重入锁
    可重⼊锁(⼜名递归锁)是指在同⼀个线程在外层⽅法获取锁的时候,再进⼊该线程的内层⽅法会⾃动获取锁(前提,锁对象得是同⼀个对象),不会因为之前已经获取过还没释放⽽阻塞。 如果是1个有synchronized修饰的递归调⽤⽅法,程序第2次进⼊被⾃⼰阻塞了岂不是天⼤的笑话,出现了作茧⾃缚......