ReentrantLock加锁和解锁

ReentrantLock详解(可重入、可中断、锁超时、公平锁、条件变量)、同步模式之顺序控制 文章目录1.ReentrantLock详解1.1 可重入1.2 可中断 lockInterruptibly()1.3 设置超时时间 tryLock()1.4 通过lock.tryLock()来解决, 哲学家就餐问题1.5 公平锁 new ReentrantLock(true)1.6 条件变量 Condition 1.ReentrantLock详解 相对于synchronized 它具备如下特点 可中断 可以设置超时时间 可以设置为公平锁 支持多个条件变量 与 synchronized 一样,都支持可重入 阅读详情

1.ReentrantLock

1.1 ReentrantLock是什么

ReentrantLock 意思为可重入锁,指的是一个线程能够对一个临界资源重复加锁。

ReentrantLock内部实现依赖于AQS。

1.2 AQS是什么

AQS(AbstractQueuedSynchronizer)是抽象队列同步器,在线程访问共享资源时候,会先判断资源是否上锁了,
如果上锁了,那么把该线程放入CLH队列中进行等待;
如果没上锁,那么把该线程设置为工作线程。

AQS的主要原理图:

AQS 使用一个 Volatile 的 int 类型的成员变量来表示同步状态,通过内置的 FIFO 队列来完成资源获取的排队工作,通过 CAS 完成对 State 值的修改。

1.3 ReentrantLock的代码结构

ReentrantLock有三个内部类:

  1. Sync:继承自AQS的同步控制基础。
  2. NonfairSync:Sync的非公平版本实现
  3. FairSync:Sync的公平版本实现

ReentrantLock默认实例化的非公平锁NonfairSync。可以通过传递false,来实例化公平锁FairSync

1.4 ReentrantLock的加锁和解锁过程

FairSync加锁过程:

调用lock()方法即可加锁。

加锁时先tryAcquire(1)尝试获取锁:

  • 如果获取成功,那么把当前线程设置为工作线程,结束加锁流程
  • 如果获取失败,那么把当前线程添加到CLH队列的队尾进行等待。

FairSync解锁过程:

调用unlock()方法即可解锁。注意,该方法一定要放在finally块中进行调用!

解锁时调用tryRelease(arg)方法

  • 如果成功,唤醒等待队列中的线程进行工作
  • 如果失败,返回false

NonFairSync加锁解锁过程:

加锁过程不同于FairSync,NonFairSync会在调用lock()时,直接尝试把state设置为1:

  • 如果失败,会调用nonfairTryAcquire()获取锁,而nonfairTryAcquire()在获取锁的时候,也不会顾及CLH队列中是否有线程在等待获取锁,从而实现非公平加锁。
  • 如果成功,直接获取锁,执行业务。

解锁过程和FairSync一致。

1.5 ReentrantLock源码解析

FairSync加锁的主要方法:

lock():
public void lock() {
	sync.lock();
}

看到lock()方法其实就是调用Sync的lock()方法,而Sync的Lock有NonFairSync和FairSync两种实现,这边先看FairSync的实现: 

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

 该方法的参数1,实际上即是state的值,1表示加锁。继续看acquire()方法:

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

acquire()调用了三个方法,分别是:

  • tryAcquire():尝试以独占模式获取锁
  • addWaiter():为当前线程和给定模式创建并排队节点。
  • acquireQueued():以独占不中断模式获取已在队列中的线程

先看tryAcquire()

protected final boolean tryAcquire(int acquires) {
    // 获取当前线程
    final Thread current = Thread.currentThread();
    // 获取state的值
    int c = getState();
    // state等于0,即共享资源没有被加锁
    if (c == 0) {
        /*
        先看队列中有没有线程在等待获取锁,
        如果没有那就设置当前线程就是工作线程
        如果有就返回false,此处体现了公平锁特性
         */
        if (!hasQueuedPredecessors() &&
                compareAndSetState(0, acquires)) {
            // 设置当前线程为独占线程
            setExclusiveOwnerThread(current);
            return true;
        }
    }
    // 如果当前工作线程是该线程,那么可以重复获取锁,并将state的值+1,此处体现了ReentrantLock是可重入锁
    else if (current == getExclusiveOwnerThread()) {
        int nextc = c + acquires;
        // int有最大值,超过最大值后,state会变成负数,因此加了这个判断
        if (nextc < 0)
            throw new Error("Maximum lock count exceeded");
        setState(nextc);
        return true;
    }
    // 共享资源被锁定,返回false
    return false;
}

这个方法的第一个if判断,提现了获取锁是公平的;第二个则体现是ReentrantLock是可重入锁。

看一下hasQueuedPredecessors()方法,

hasQueuedPredecessors():

public final boolean hasQueuedPredecessors() {
    Node t = tail; 
    Node h = head;
    Node s;
    // 头结点不等于尾节点,并且,(头结点的next不为null,或者next的线程不是当前线程)
    return h != t &&
            ((s = h.next) == null || s.thread != Thread.currentThread());
}

 该方法的解析:https://blog.youkuaiyun.com/weixin_38106322/article/details/107154961

addWaiter():

private Node addWaiter(Node mode) {
    // 把当前线程作为入参创建一个Node节点
    Node node = new Node(Thread.currentThread(), mode);
    // Try the fast path of enq; backup to full enq on failure
    Node pred = tail;
    // 如果队列的尾节点不为null,把node添加到队尾
    if (pred != null) {
        node.prev = pred;
        // cas设置尾节点
        if (compareAndSetTail(pred, node)) {
            pred.next = node;
            return node;
        }
    }
    // 将节点插入队列,如果队列为空则初始化队列 
    enq(node);
    return node;
}

addWaiter(),就是把当前线程添加到队列中。 其中的enq()是在快速添加node到队尾失败才会调用,而这个方法也是添加node到队列中。

acquireQueued():

final boolean acquireQueued(final Node node, int arg) {
    // 标记是否成功拿到资源
    boolean failed = true;
    try {
        // 标记等待过程中是否中断过
        boolean interrupted = false;
        // 开始自旋,要么获取锁,要么中断
        for (;;) {
            // 获取当前节点的前节点
            final Node p = node.predecessor();
            // 如果前节点是头结点(工作节点)并且tryAcquire()成功
            if (p == head && tryAcquire(arg)) {
                // 把node设置为头结点
                setHead(node);
                p.next = null; // help GC
                failed = false;
                return interrupted;
            }
            // 靠前驱节点判断当前线程是否应该被阻塞
            if (shouldParkAfterFailedAcquire(p, node) &&
                    // 阻塞当前节点
                    parkAndCheckInterrupt())
                interrupted = true;
        }
    } finally {
        // 如果执行失败,则把这个节点状态设置为取消状态
        if (failed)
            cancelAcquire(node);
    }
}

 这边多了shouldParkAfterFailedAcquire()和parkAndCheckInterrupt()方法。

shouldParkAfterFailedAcquire():靠前驱节点判断当前线程是否应该被阻塞

parkAndCheckInterrupt():阻塞当前节点

// 靠前驱节点判断当前线程是否应该被阻塞
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
	// 获取头结点的节点状态
	int ws = pred.waitStatus;
	// 说明头结点处于唤醒状态
	if (ws == Node.SIGNAL)
		return true;
	// 通过枚举值我们知道waitStatus>0是取消状态
	if (ws > 0) {
		do {
			// 循环向前查找取消节点,把取消节点从队列中剔除
			node.prev = pred = pred.prev;
		} while (pred.waitStatus > 0);
		pred.next = node;
	} else {
		// 设置前任节点等待状态为SIGNAL
		compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
	}
	return false;
}
private final boolean parkAndCheckInterrupt() {
    // 阻塞当前线程
    LockSupport.park(this);
    // 当前线程被唤醒后,返回线程的中断状态,然后重置中断状态
    return Thread.interrupted();
}

FairSync解锁的主要方法:

在调用lock.unlock()时候,内部调用的是Sync的release()方法,源码:

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

release(): 

public final boolean release(int arg) {
    // 释放锁
    if (tryRelease(arg)) {
        Node h = head;
        // 如果当前头结点不为null,并且waitStatus不是0(无锁状态)
        if (h != null && h.waitStatus != 0)
            // 唤醒下一个线程开展业务
            unparkSuccessor(h);
        return true;
    }
    return false;
}

release()会调用tryRelease()方法:

  • 如果返回tryRelease()false,那么release()直接返回false
  • 如果返回true,进行判断后,会唤醒队列中下一个线程进行工作

tryRelease():

protected final boolean tryRelease(int releases) {
    // 获取state的值,并且减去1(releases等于1)
    int c = getState() - releases;
    // 判断当前线程是不是工作线程,如果不是,抛出异常
    if (Thread.currentThread() != getExclusiveOwnerThread())
        throw new IllegalMonitorStateException();
    // 共享资源是否空闲的标记
    boolean free = false;
    // 如果state为0(空闲)
    if (c == 0) {
        // 设置空闲标记为true,并把当前工作线程设置为null
        free = true;
        setExclusiveOwnerThread(null);
    }
    // 设置state等于0
    setState(c);
    return free;
}

tryRelease()会释放一次锁,不过ReentrantLock是可重入锁,因此释放一次后,共享资源不一定会处于空闲状态。

unparkSuccessor():

private void unparkSuccessor(Node node) {
	// 获取头结点waitStatus
	int ws = node.waitStatus;
	if (ws < 0)
		compareAndSetWaitStatus(node, ws, 0);
	// 获取当前节点的下一个节点
	Node s = node.next;
	// 如果下个节点是null或者下个节点被cancelled,就找到队列最开始的非cancelled的节点
	if (s == null || s.waitStatus > 0) {
		s = null;
		// 就从尾部节点开始找,到队首,找到队列第一个waitStatus<0的节点。
		for (Node t = tail; t != null && t != node; t = t.prev)
			if (t.waitStatus <= 0)
				s = t;
	}
	// 如果当前节点的下个节点不为空,而且状态<=0,就把当前节点unpark
	if (s != null)
		LockSupport.unpark(s.thread);
}

unparkSuccessor()就是唤醒线程进行工作。只有当唤醒下一个线程后,release()方法才会返回true。

NonFairSync加锁的主要方法:

对比FairSync的源码,会发现两者的区别就是在于lock方法:

 lock():

final void lock() {
    // 第一步直接尝试设置state的值(不公平啊)
    if (compareAndSetState(0, 1))
        // 设置成功,设置当前线程为工作线程
        setExclusiveOwnerThread(Thread.currentThread());
    else
        // 设置失败,再去尝试获取锁
        acquire(1);
}

 不公平锁加锁时,会直接尝试设置state的值。

再看acquire()方法,

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

可以看到和FairSync的acquire()方法一样,唯一不同的是tryAcquire()的不同;

tryAcquire():

protected final boolean tryAcquire(int acquires) {
    return nonfairTryAcquire(acquires);
}

tryAcquire()调用的是nonfairTryAcquire(),

nonfairTryAcquire():

final boolean nonfairTryAcquire(int acquires) {
    // 获取当前线程
    final Thread current = Thread.currentThread();
    int c = getState();
    // 如果共享资源处于空闲状态
    if (c == 0) {
        // 尝试设置直接设置state(不管队列中是否有排队的线程直接就插队,不公平啊)
        if (compareAndSetState(0, acquires)) {
            // 设置state成功,就把当前线程设置为工作线程
            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;
}

对比FairSync的tryAcquire()方法和nonfairTryAcquire()方法,可以看出唯一的区别就是nonfairTryAcquire()方法少了一个hasQueuedPredecessors()的判断,这个判断是判断CLH队列中有没有线程在等待获取资源。而非公平锁就不管等待队列是否有等待线程,直接去尝试获取资源(不公平)。

2.相关问题

1.lock.lock()是怎么锁定资源的?
通过AQS中变量state的值来判断这个资源有没有被锁定。
当代码执行到lock.lock()时,会判断state的值,
如果state等于0,那么获取锁并将state设置为1。
如果state不等于0,但是当前线程就是加锁线程,那么获取锁定资源,并把state+1
否则,调用LockSupport.park(this),把当前线程挂起。获取锁定资源时候,会把当前线程设置为独占线程。

 2.lock.unlock()是怎么释放锁的?
先把state-1,并判断当前线程是不是独占线程,如果不是,抛出IllegalMonitorStateException异常
然后判断state是否为0?
如果等于0,把独占线程设置null,并返回true
如果不等于0,把state值设置为新的state,并返回false

3.锁被释放后,如何通知队列中的线程过来工作的?
在调用unlock()时候,如果tryRelease()成功,并且head节点不为null和head节点的waitStatus不等于0(0是初始值)
这时会调用LockSupport.unpark(s.thread)唤醒等待节点过来工作

4.等待线程被唤醒后工作后,会不会从CLH队列中移除
在等待线程被唤醒后工作后,会把头结点设置这个等待节点,等待节点会被设置为头结点,并把之前头结点的next指针指向null

5.ReentrantLock中公平锁和不公平锁的区别?
ReentrantLock中有两个内部类,分别是:NonfairSync(不公平锁)、FairSync(公平锁),ReentrantLock默认实例化的是不公平锁。
FairSync:加锁的时候会进行先看state是否等于0,如果是,那么会再去看队列中有没有线程在等待执行,如果有,那么就加入队尾等待执行。如果没有,才执行线程
NonfairSync:加锁时,先尝试设置state为1,成功则获取锁,否则则再去获取state的值,如果此时state等于0,那么直接获取锁,不管队列中是否还有没有线程在等待执行。如果不等于0,那么该线程加入队尾排队执行。
因此:
两个锁的区别在于加锁的时候。除此之外,其他逻辑一样。

6.AQS原理
AQS是抽象队列同步器,在线程访问共享资源时候,会先判断资源是否上锁了,
如果上锁了,那么把该线程放入CLH队列中进行等待;
如果没上锁,那么把该线程设置为工作线程。

7.Reentrantlock中的condition的使用方法和原理?
使用lock.newCondition();可以构造一个condition对象。
condition主要作用于线程之间通讯,功能类似Object的wait()和notify()
每个condition内部维护了队列,队列存放等待执行的线程,每调用一次condition.await(),队列都会增加,调用conditionA.signal();队列会移除元素。
condition.await();使当前线程等待,直到它被通知或中断。该方法会释放当前锁,并将当前线程放入CLH队列队尾中进行等待,然后唤醒condition中队列的第一个元素。
conditionA.signal();唤醒一个等待的线程。唤醒condition中队列的第一个元素。

8.独占锁和共享锁的区别?
独占锁:独占锁也叫排他锁,是指该锁一次只能被一个线程所持有。如果线程T对数据A加上排他锁后,则其他线程不能再对A加任何类型的锁。获得排它锁的线程即能读数据又能修改数据。
ReentrantLock 和 synchronized 都是独占锁
共享锁:共享锁是指该锁可被多个线程所持有。如果线程T对数据A加上共享锁后,则其他线程只能对A再加共享锁,能加排它锁。获得共享锁的线程只能读数据,能修改数据。
独享锁与共享锁也是通过AQS来实现的,通过实现不同的方法,来实现独享或者共享。
ReentrantReadWriteLock:读锁是共享锁,写锁是独占锁。读锁的共享可以保证并发读是高效的,读写,写读,写写是互斥的

AM243x多核MCU启动流程解析与OSPI Flash烧录实战 嵌入式系统开发中,引导加载器是芯片上电后执行的第一段软件,负责初始化硬件、加载操作系统或应用程序。其工作原理通常遵循多级引导链,从ROM固件到用户可定制的二级引导程序,逐级建立完整的软件运行环境。这一机制的技术价值在于实现可靠的系统启动、支持安全校验,并为多核异构架构提供协同基础。在应用场景上,引导加载器广泛应用于工业控制、汽车电子和物联网设备,确保设备能从非易失性存储器中自主启动。本文聚焦于TI AM243x这类高性能多核MCU,深入剖析其包含RBL和SBL在内的三级启动流程,并详细演示如何通过UART接 阅读详情

相关推荐

多节阶梯阻抗变换器工程设计的公式推导

  多节阶梯阻抗变换器工程设计的公式推导,仔细看此文,有点烧脑,所以碎片十分钟,收获一丢丢。   现在就来设计一个超宽带多节阶梯阻抗变换器,要求带内纹波符合切比雪夫分布。   其实,此文已经是省去了大量中间公式推导,只剩下精炼内容了。   阶梯阻抗变换器指标需求   假设现在有一项目需求分析结果是:做一个微带线超宽带阶梯阻抗变换器,指标如下:   从50欧变换到100欧;   回波损耗22dB;   功率容量:2W;   频率范围2~18GHz;   插损能做多少就多少,用30mil板厚.

wusuowei1010的博客 7811

20张图带你彻底了解ReentrantLock加锁解锁的原理

1.代码使用要合乎规范,避免加锁成功后,在finally中无法解锁; 2.理解AQS的FIFO队列以及Node的相关属性,尤其注意waitStatus的状态; 3.利用图加深对非公平锁源码的理解;

阿Q的小窝 1162

实战指南:利用 LangGraph 的状态管理实现多轮对话的上下文隔离与持久化

本文详细介绍了如何利用LangGraph的状态管理机制,高效实现多轮对话中的上下文隔离与持久化。通过实战代码演示,从基础的消息历史管理到自定义状态扩展,再到使用SQLite进行生产级持久化,系统讲解了如何借助LangGraph的State和Checkpointer自动化处理对话记忆、用户隔离及数据存储,显著提升开发效率。

weixin_28396629的博客 490

【图解】一文搞定ReentrantLock加锁、解锁过程

②再来看第二个方法addWaiter(Node mode)首先将当前线程封装成一个node节点,首先判断tail节点如果不为空,将当前节点的前驱节点设置为tail,然后用CAS尝试更新tail指向当前节点,如果更新成功则将tail的后置节点指向当前节点,最后返回当前节点,如果tail节点为空,将当前节点进行入队操作enq(node)

qq_38614925的博客 1668

Xilinx同步FIFO IP核的两种读模式对比:Standard vs FWFT(附Vivado仿真代码)

本文深入解析Xilinx同步FIFO IP核的两种读模式——Standard与FWFT,通过时序仿真和Vivado代码示例对比其性能差异。Standard模式适合严格流水线设计,而FWFT模式在低延迟场景表现更优。文章包含详细的testbench搭建指南和性能实测数据,帮助FPGA工程师优化数据流设计。

table的专栏 348

Python实战:5分钟搞定N-CMAPSS航空发动机数据集解析(附完整代码)

本文提供了一份针对N-CMAPSS航空发动机数据集的快速解析实战指南。通过Python的h5py和Pandas库,详细演示了如何高效读取HDF5格式文件、理解数据结构、提取关键特征(如传感器数据与剩余使用寿命RUL),并整合为可用于预测性维护分析的DataFrame,帮助研究者和工程师快速上手这一重要的工业时序数据集。

weixin_29083373的博客 281

ReentrantLock加锁解锁剖析

AbstractQueuedSynchronizer有一个内部类Node,底层维护了一个双向链表而形成一个队列。也就是我们的AQS队列。当我们获取锁失败后的线程会被放到这个队列中,等待其他线程释放lock的时候被唤醒。ReentrantLock整个加锁过程就是围绕着state属性来进行的。当state字段大于0时,代表当前资源被锁住,并且state的值代表当前持有锁线程的重入次数,当state为0时,队列中的线程就可以通过一系列的CAS操作来争抢这个锁。

weixin_51389615的博客 1万+

Windows下用Anaconda安装d2l库避坑指南(附PermissionError解决方案)

本文详细介绍了在Windows系统下使用Anaconda安装d2l库的完整指南,特别针对常见的PermissionError问题提供了多种解决方案。从环境准备到库安装,再到VSCode配置和数据路径处理,帮助读者顺利搭建深度学习环境并运行《动手学深度学习》的代码示例。

3a9bq4r8t2y的博客 226

ReentrantLock源码分析(一)加锁流程分析

线程C过来后,由于线程A已经抢占到锁资源,并且其业务代码需要执行5s中,那么此时线程c也无法抢到锁,需要进行进入AQS队列操作。然后在线程A启动后先睡眠1秒再启动B线程,线程B启动后睡眠1秒再启动线程C。放入到双向队列的时候,前面需要有一个伪头节点(节点中thread为null,waitStatus = -1),B放入进入后对应的node节点属性(thread = 线程B,waitStatus = 0)线程B执行加锁操作的时候,由于锁已经被线程A占有了,所以没抢占到,执行进入AQS队列操作。

zhangshenglu1的博客 627

硬件学习笔记(器件篇)—— 磁珠与磁环

因为有这些差别,所有经常会让人们觉得他们并不是一类器件,但实际上他们的原理是一样的。我们使用磁珠是为了利用损耗消耗高频能量,所以如果我们理解了磁珠是如何消耗高频能量的,我们就能理解磁珠的工作原理。

y_u_yu_yu_的博客 1万+

2ED2410-EM:12v / 24v智能模拟高侧MOSFET栅极驱动器

12v / 24v智能模拟高侧MOSFET栅极驱动器。2ED2410-EM具有输入CPP和CPN的电压比较器。该比较器可用于基于任何模拟电压触发SAFESTATE模式,甚至是外部电压2ED2410-EM。CPP为比较器的正输入,CPN为负输入。VcPREF可以通过微控制器进行调节,也可以通过板载电源芯片(如英飞凌SBC)或简单的分压器在限制VcP(REF)内进行固定,以保持稳定性。使用此比较器允许2ED2410-EM进入SAFESTATE并独立于微控制器关闭MOSFET。

让学习成为一种习惯 2200

ReentrantLock 加锁与解锁流程详解(源码分析,小白易懂)

摘要: 本文详细解析了ReentrantLock的加锁解锁机制。加锁时,成功则修改state为1并设置独占线程;失败则构建Node队列,线程进入阻塞等待。解锁时,释放锁后唤醒队列中的等待线程,新线程可能通过非公平竞争抢占锁。整个过程涉及tryAcquire、addWaiter、acquireQueued等关键步骤,以及waitStatus状态变化,展现了ReentrantLock底层AQS实现的核心原理。

先做到 再看见 1248

Allan方差这个工具,怎么把它用的更顺手?(附Allan方差、动态Allan方差代码)

本文详细说明了Allan方差和动态Allan方差的计算过程,并通过递归运算和时间序列选择两种算法提高动态Allan方差的计算效率。文末提供了快速动态Allan方差计算代码。

victoryqian528的博客 374

ReentrantLock 加锁解锁原理

可中断(在获取锁失败后,阻塞等待锁的过程,这个阻塞状态,是可以被打断的,打断后会抛出异常)可超时(有时限的等待)可公平(可以设置为公平锁,让来获取线程的锁先到先得)支持多个条件变量(synchronized对对象加锁,关联操作系统的一个Monitor,一个Monitor只有1个WaitSet,所有wait的线程都到这个WaitSet中等待,而ReentrantLock相当于可以有多个WaitSet)ReentrantLock和synchronized都支持可重入。

csdn_clwjc的博客 987

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

【图解】一篇搞定ReentrantLock的加锁和解锁过程

文章目录1. 概述2. AbstractQueuedSynchronizer(AQS)3. 加锁4. 解锁5. 公平锁和非公平锁的区别 1. 概述 本文主要结合图片分析ReentrantLock加锁和解锁过程的源码,加锁和解锁的原理不清楚的读者可以好好看看。 2. AbstractQueuedSynchronizer(AQS) 在分析ReentrantLock加锁和解锁的过程之前,先来了解一下AQS,ReentrantLock就是基于AQS实现的。AQS其实就是维护了一个双向链表,主要的属性如下所示: T

gongsenlin341的博客 2701

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

并发编程(二十)-ReentrantLock 加锁、解锁原理

并发编程(二十)-ReentrantLock 加锁、解锁原理

及时当勉励,岁月不待人 909

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

深入理解 JUC 的 ReentrantLock 加锁和解锁流程

下面这张图 你需要明白的是先讲解一下大概的流程ReentrantLock 首先lock-》 公平锁或者非公平锁的 lock()-》acquire(1) 就会跑到AQS的代码中。

sjisbbeksudh的博客 523

ReentrantLock的加锁和解锁原理

ReentrantLock的实现依赖于Java同步器框架AQS。 AQS使用一个整型的volatile变量(命名为state)来维护同步状态。 ReentrantLock分为公平锁和非公平锁 公平锁 使用公平锁时,加锁方法lock()的调用轨迹: ReentrantLock:lock() FairSync:lock() AbstractQueuedSynchronizer:acquire...

Keyu 1363

并发编程:ReentrantLock的加锁和解锁过程

ReentrantLock1. 和Aqs的关系2. 非公平锁加锁流程 1. 和Aqs的关系 2. 非公平锁加锁流程 第一个线程t1,第一次加锁,没有加锁之前 aqs(NonfairSync)的状态 2. t1加锁成功后 3. 第二个线程t2尝试加锁,如果加锁成功 4. t2加锁失败,会创建队列 t == null队列还没有创建; compareAndSetHead(new Node())创建一个Thread=null的head; node.prev = t; t2节点的prev指向head;

Fisher3652的博客 766

ReentrantLock加锁解锁线程入队源码分析

本文介绍ReentrantLock加锁解锁过程 在看这个类的代码时,先看类的关系,ReentrantLock,内部有sync类,继承了AbstractQueuedSynchronizer,这个类中封装很多锁的公共方法,比如,获取锁,释放锁,创建队列,入队,阻塞,共享锁的逻辑。 测试代码: import java.util.concurrent.locks.ReentrantLock; public class TestLock { public static void main(Strin

wangfenglei123456的博客 827

java中synchronized和ReentrantLock的加锁和解锁能在不同线程吗?如果能,如何实现?

java中synchronized和ReentrantLock都是可重入锁,所以在线程上的加锁和解锁会做限制,加锁和解锁必须在同一线程,并且成对出现。go的sync.Mutex是不可重入锁,所以在协程上的加锁和解锁没做限制。加锁和解锁可以不在同一协程,但要成对出现。

福大大架构师每日一题 2万+

ReentrantLock加锁解锁源码分析及避坑总结

如题一句话总结先看构造方法,默认执行非公平锁非公平锁加锁方法 一句话总结 谨以此文送给懒得思考源码的新人,包括曾经的自己。 先看构造方法,默认执行非公平锁 //先看构造方法,默认执行非公平锁 public ReentrantLock() { sync = new NonfairSync(); } 执行公平锁的构造方法 public ReentrantLock(boolean fair) { sync = fair ? new FairSync() : new NonfairSync(); } 非公平

c0d5r的博客 321

ReentrantLock加锁解锁的过程

文章目录简介与synchronized相比    相同点    不同点构造方法加锁 简介     ReentrantLock是一种基于AQS框架的应用实现,是JDK中的一种保证线程并发安全的同步手段,它的功能类似于synchronized是一种互斥锁,可以保证线程安全. 与synchronized相比     相同点 都是独占锁的实现 都是可重入锁

一个菜鸟的博客 493

『每日一问』ReentrantLock加锁解锁

Lock接口中有六个方法 void lock(); void lockInterruptibly() throws InterruptedException; Condition newCondition(); boolean tryLock(); boolean tryLock(long time, TimeUnit unit) throws InterruptedException; void unlock(); 加锁 ReentrantLock.lock public void lock() .

轰鸣 367

AQS之ReentrantLock加锁解锁

加锁解锁?

weixin_46051077的博客 303

【AQS源码解析】ReentrantLock的公平锁加锁解锁分析

引言 ​ AQS是用来构建锁和其他同步组件的基础框架,它也是Java三大并发工具类(CountDownLatch、CyclicBarrier、Semaphore)的基础。ReentrantLock,甚至BlockingQueue也是基于它的实现。本文从ReentrantLock的lock()出发,从源码维度分析一个加锁解锁动作都干了什么事。 ​ 公平锁:多个线程按照申请锁的顺序去获得锁,线程会直接进入队列去排队,永远都是队列的第一位才能得到锁。 ​ 非公平锁:多个线程去获取锁的时候,会直接去尝试获取,

a1850568889的博客 679
上一篇: mysql8分组后排序
下一篇: ThreadLocal源码分析
Yuwen_forJava
博客等级 码龄9年 28粉丝 90原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值