这篇 ReentrantLock 看不懂,加我我给你发红包

Java面试进阶:从八股文到知识体系,构建问题链思维应对高并发与系统设计 在软件开发领域,构建稳固的知识体系是工程师应对复杂挑战的核心能力。其原理在于将零散的技术概念通过逻辑关联形成网络,从而提升问题分析与解决效率。这种系统化思维的技术价值在于,它能将基础理论转化为工程实践,帮助开发者从被动记忆转向主动应用。在典型的应用场景如高并发系统设计中,面对秒杀超卖、缓存一致性等高频问题,开发者需要串联起并发编程、数据库事务、分布式缓存及系统架构等多层知识。例如,解决超卖问题不仅涉及Java中的synchronized与CAS机制,更需理解Redis分布式锁的实现细节与数据库行锁原理,这正 阅读详情

Github上最值得学习的100个Java开源项目,涵盖各种技术栈!

2020年最新的常问企业面试题大全以及答案

回答一个问题

在开始本篇文章的内容讲述前,先来回答我一个问题,为什么 JDK 提供一个 synchronized 关键字之后还要提供一个 Lock 锁,这不是多此一举吗?难道 JDK 设计人员都是沙雕吗?

我听过一句话非常的经典,也是我认为是每个人都应该了解的一句话:你以为的并不是你以为的。明白什么意思么?不明白的话,加我微信我告诉你。

初识 ReentrantLock

ReentrantLock 位于 java.util.concurrent.locks 包下,它实现了 Lock 接口和 Serializable 接口。

ReentrantLock 是一把可重入锁和互斥锁,它具有与 synchronized 关键字相同的含有隐式监视器锁(monitor)的基本行为和语义,但是它比 synchronized 具有更多的方法和功能。

ReentrantLock 基本方法

构造方法

ReentrantLock 类中带有两个构造函数,一个是默认的构造函数,不带任何参数;一个是带有 fair 参数的构造函数

public ReentrantLock() {
  sync = new NonfairSync();
}

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

第二个构造函数也是判断 ReentrantLock 是否是公平锁的条件,如果 fair 为 true,则会创建一个公平锁的实现,也就是 new FairSync(),如果 fair 为 false,则会创建一个 非公平锁的实现,也就是 new NonfairSync(),默认的情况下创建的是非公平锁

// 创建的是公平锁
private ReentrantLock lock = new ReentrantLock(true);

// 创建的是非公平锁
private ReentrantLock lock = new ReentrantLock(false);

// 默认创建非公平锁
private ReentrantLock lock = new ReentrantLock();

FairSync 和 NonfairSync 都是 ReentrantLock 的内部类,继承于 Sync 类,下面来看一下它们的继承结构,便于梳理。

abstract static class Sync extends AbstractQueuedSynchronizer {...}

static final class FairSync extends Sync {...}
  
static final class NonfairSync extends Sync {...}

在多线程尝试加锁时,如果是公平锁,那么锁获取的机会是相同的。否则,如果是非公平锁,那么 ReentrantLock 则不会保证每个锁的访问顺序。

下面是一个公平锁的实现

public class MyFairLock extends Thread{

    private ReentrantLock lock = new ReentrantLock(true);
    public void fairLock(){
        try {
            lock.lock();
            System.out.println(Thread.currentThread().getName()  + "正在持有锁");
        }finally {
            System.out.println(Thread.currentThread().getName()  + "释放了锁");
            lock.unlock();
        }
    }

    public static void main(String[] args) {
        MyFairLock myFairLock = new MyFairLock();
        Runnable runnable = () -> {
            System.out.println(Thread.currentThread().getName() + "启动");
            myFairLock.fairLock();
        };
        Thread[] thread = new Thread[10];
        for(int i = 0;i < 10;i++){
            thread[i] = new Thread(runnable);
        }
        for(int i = 0;i < 10;i++){
            thread[i].start();
        }
    }
}

不信?不信你输出试试啊!懒得输出?就知道你懒得输出,所以直接告诉你结论吧,结论就是自己试。

试完了吗?试完了我是不会让你休息的,过来再试一下非公平锁的测试和结论,知道怎么试吗?上面不是讲过要给 ReentrantLock 传递一个参数的吗?你想,传 true 的时候是公平锁,那么反过来不就是非公平锁了?其他代码还用改吗?不需要了啊。

明白了吧,再来测试一下非公平锁的流程,看看是不是你想要的结果。

公平锁的加锁(lock)流程详解

通常情况下,使用多线程访问公平锁的效率会非常低(通常情况下会慢很多),但是 ReentrantLock 会保证每个线程都会公平的持有锁,线程饥饿的次数比较小。锁的公平性并不能保证线程调度的公平性。

此时如果你想了解更多的话,那么我就从源码的角度跟你聊聊如何 ReentrantLock 是如何实现这两种锁的。

如上图所示,公平锁的加锁流程要比非公平锁的加锁流程简单,下面要聊一下具体的流程了,请小伙伴们备好板凳。

下面先看一张流程图,这张图是 acquire 方法的三条主要流程

首先是第一条路线,tryAcquire 方法,顾名思义尝试获取,也就是说可以成功获取锁,也可以获取锁失败。

使用 ctrl+左键 点进去是调用 AQS 的方法,但是 ReentrantLock 实现了 AQS 接口,所以调用的是 ReentrantLock 的 tryAcquire 方法;

首先会取得当前线程,然后去读取当前锁的同步状态,还记得锁的四种状态吗?分别是 无锁、偏向锁、轻量级锁和重量级锁,如果你不是很明白的话,请参考博主这篇文章(不懂什么是锁?看看这篇你就明白了),如果判断同步状态是 0 的话,就证明是无锁的,参考下面这幅图( 1bit 表示的是是否偏向锁 )

如果是无锁(也就是没有加锁),说明是第一次上锁,首先会先判断一下队列中是否有比当前线程等待时间更长的线程(hasQueuedPredecessors);然后通过 CAS 方法原子性的更新锁的状态,CAS 方法更新的要求涉及三个变量,currentValue(当前线程的值),expectedValue(期望更新的值),updateValue(更新的值),它们的更新如下

if(currentValue == expectedValue){
  currentValue = updateValue
}

CAS 通过 C 底层机制保证原子性,这个你不需要考虑它。如果既没有排队的线程而且使用 CAS 方法成功的把 0 -> 1 (偏向锁),那么当前线程就会获得偏向锁,记录获取锁的线程为当前线程。

然后我们看 else if 逻辑,如果读取的同步状态是1,说明已经线程获取到了锁,那么就先判断当前线程是不是获取锁的线程,如果是的话,记录一下获取锁的次数 + 1,也就是说,只有同步状态为 0 的时候是无锁状态。如果当前线程不是获取锁的线程,直接返回 false。

acquire 方法会先查看同步状态是否获取成功,如果成功则方法结束返回,也就是 !tryAcquire == false ,若失败则先调用 addWaiter 方法再调用 acquireQueued 方法

然后看一下第二条路线 addWaiter

这里首先把当前线程和 Node 的节点类型进行封装,Node 节点的类型有两种,EXCLUSIVE 和 SHARED ,前者为独占模式,后者为共享模式,具体的区别我们会在 AQS 源码讨论,这里读者只需要知道即可。

首先会进行 tail 节点的判断,有没有尾节点,其实没有头节点也就相当于没有尾节点,如果有尾节点,就会原子性的将当前节点插入同步队列中,再执行 enq 入队操作,入队操作相当于原子性的把节点插入队列中。

如果当前同步队列尾节点为null,说明当前线程是第一个加入同步队列进行等待的线程。

在看第三条路线 acquireQueued

主要会有两个分支判断,首先会进行无限循环中,循环中每次都会判断给定当前节点的先驱节点,如果没有先驱节点会直接抛出空指针异常,直到返回 true。

然后判断给定节点的先驱节点是不是头节点,并且当前节点能否获取独占式锁,如果是头节点并且成功获取独占锁后,队列头指针用指向当前节点,然后释放前驱节点。如果没有获取到独占锁,就会进入 shouldParkAfterFailedAcquire 和 parkAndCheckInterrupt 方法中,我们贴出这两个方法的源码

shouldParkAfterFailedAcquire 方法主要逻辑是使用compareAndSetWaitStatus(pred, ws, Node.SIGNAL)使用CAS将节点状态由 INITIAL 设置成 SIGNAL,表示当前线程阻塞。当 compareAndSetWaitStatus 设置失败则说明 shouldParkAfterFailedAcquire 方法返回 false,然后会在 acquireQueued 方法中死循环中会继续重试,直至compareAndSetWaitStatus 设置节点状态位为 SIGNAL 时 shouldParkAfterFailedAcquire 返回 true 时才会执行方法 parkAndCheckInterrupt 方法。(这块在后面研究 AQS 会细讲)

parkAndCheckInterrupt 该方法的关键是会调用 LookSupport.park 方法(关于LookSupport会在以后的文章进行讨论),该方法是用来阻塞当前线程。

所以 acquireQueued 主要做了两件事情:如果当前节点的前驱节点是头节点,并且能够获取独占锁,那么当前线程能够获得锁该方法执行结束退出

如果获取锁失败的话,先将节点状态设置成 SIGNAL,然后调用 LookSupport.park 方法使得当前线程阻塞。

如果 !tryAcquire 和 acquireQueued 都为 true 的话,则打断当前线程。

那么它们的主要流程如下(注:只是加锁流程,并不是 lock 所有流程)

非公平锁的加锁(lock)流程详解

非公平锁的加锁步骤和公平锁的步骤只有两处不同,一处是非公平锁在加锁前会直接使用 CAS 操作设置同步状态,如果设置成功,就会把当前线程设置为偏向锁的线程;一处是 CAS 操作失败执行 tryAcquire 方法,读取线程同步状态,如果未加锁会使用 CAS 再次进行加锁,不会等待 hasQueuedPredecessors 方法的执行,达到只要线程释放锁就会加锁的目的。下面通过源码和流程图来详细理解

这是非公平锁和公平锁不同的两处地方,下面是非公平锁的加锁流程图

lockInterruptibly 以可中断的方式获取锁

以下是 JavaDoc 官方解释:

lockInterruptibly 的中文意思为如果没有被打断,则获取锁。如果没有其他线程持有该锁,则获取该锁并立即返回,将锁保持计数设置为1。如果当前线程已经持有锁,那么此方法会立刻返回并且持有锁的数量会 + 1。如果锁是由另一个线程持有的,则出于线程调度目的,当前线程将被禁用,并处于休眠状态,直到发生以下两种情况之一

  • 锁被当前线程持有

  • 一些其他线程打断了当前线程

如果当前线程获取了锁,则锁保持计数将设置为1。

如果当前线程发生了如下情况:

  • 在进入此方法时设置了其中断状态

  • 当获取锁的时候发生了中断(Thread.interrupt)

那么当前线程就会抛出InterruptedException 并且当前线程的中断状态会清除。

下面看一下它的源码是怎么写的

首先会调用 acquireInterruptibly 这个方法,判断当前线程是否被中断,如果中断抛出异常,没有中断则判断公平锁/非公平锁 是否已经获取锁,如果没有获取锁(tryAcquire 返回 false)则调用 doAcquireInterruptibly 方法,这个方法和 acquireQueued 方法没什么区别,就是线程在等待状态的过程中,如果线程被中断,线程会抛出异常。

下面是它的流程图

tryLock 尝试加锁

仅仅当其他线程没有获取这把锁的时候获取这把锁,tryLock 的源代码和非公平锁的加锁流程基本一致,它的源代码如下

tryLock 超时获取锁

ReentrantLock除了能以中断的方式去获取锁,还可以以超时等待的方式去获取锁,所谓超时等待就是线程如果在超时时间内没有获取到锁,那么就会返回false,而不是一直死循环获取。可以使用 tryLock 和 tryLock(timeout, unit)) 结合起来实现公平锁,像这样

if (lock.tryLock() || lock.tryLock(timeout, unit)) {...}

如果超过了指定时间,则返回值为 false。如果时间小于或者等于零,则该方法根本不会等待。

它的源码如下

首先需要了解一下 TimeUnit 工具类,TimeUnit 表示给定粒度单位的持续时间,并且提供了一些用于时分秒跨单位转换的方法,通过使用这些方法进行定时和延迟操作。

toNanos 用于把 long 型表示的时间转换成为纳秒,然后判断线程是否被打断,如果没有打断,则以公平锁/非公平锁 的方式获取锁,如果能够获取返回true,获取失败则调用doAcquireNanos方法使用超时等待的方式获取锁。在超时等待获取锁的过程中,如果等待时间大于应等待时间,或者应等待时间设置不合理的话,返回 false。

这里面以超时的方式获取锁也可以画一张流程图如下

unlock 解锁流程

unlock 和 lock 是一对情侣,它们分不开彼此,在调用 lock 后必须通过 unlock 进行解锁。如果当前线程持有锁,在调用 unlock 后,count 计数将减少。如果保持计数为0就会进行解锁。如果当前线程没有持有锁,在调用 unlock 会抛出 IllegalMonitorStateException 异常。下面是它的源码

在有了上面阅读源码的经历后,相信你会很快明白这段代码的意思,锁的释放不会区分公平锁还是非公平锁,主要的判断逻辑就是 tryRelease 方法,getState 方法会取得同步锁的重入次数,如果是获取了偏向锁,那么可能会多次获取,state 的值会大于 1,这时候 c 的值 > 0 ,返回 false,解锁失败。如果 state = 1,那么 c = 0,再判断当前线程是否是独占锁的线程,释放独占锁,返回 true,当 head 指向的头结点不为 null,并且该节点的状态值不为0的话才会执行 unparkSuccessor 方法,再进行锁的获取。

ReentrantLock 其他方法

isHeldByCurrentThread & getHoldCount

在多线程同时访问时,ReentrantLock 由最后一次成功锁定的线程拥有,当这把锁没有被其他线程拥有时,线程调用 lock() 方法会立刻返回并成功获取锁。如果当前线程已经拥有锁,这个方法会立刻返回。可以通过 isHeldByCurrentThread 和 getHoldCount 来进行检查。

首先来看 isHeldByCurrentThread 方法

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

根据方法名可以略知一二,是否被当前线程持有,它用来询问锁是否被其他线程拥有,这个方法和 Thread.holdsLock(Object) 方法内置的监视器锁相同,而 Thread.holdsLock(Object) 是 Thread 类的静态方法,是一个 native 类,它表示的意思是如果当前线程在某个对象上持有 monitor lock(监视器锁) 就会返回 true。这个类没有实际作用,仅仅用来测试和调试所用。例如

private ReentrantLock lock = new ReentrantLock();

public void lock(){
  assert lock.isHeldByCurrentThread();
}

这个方法也可以确保重入锁能够表现出不可重入的行为

private ReentrantLock lock = new ReentrantLock();

public void lock(){
  assert !lock.isHeldByCurrentThread();
  lock.lock();
  try {
    // 执行业务代码
  }finally {
    lock.unlock();
  }
}

如果当前线程持有锁则 lock.isHeldByCurrentThread() 返回 true,否则返回 false。

我们在了解它的用法后,看一下它内部是怎样实现的,它内部只是调用了一下  sync.isHeldExclusively(),sync 是 ReentrantLock 的一个静态内部类,基于 AQS 实现,而 AQS 它是一种抽象队列同步器,是许多并发实现类的基础,例如 ReentrantLock/Semaphore/CountDownLatch。sync.isHeldExclusively() 方法如下

protected final boolean isHeldExclusively() {
  return getExclusiveOwnerThread() == Thread.currentThread();
}

此方法会在拥有锁之前先去读一下状态,如果当前线程是锁的拥有者,则不需要检查。

getHoldCount()方法和isHeldByCurrentThread 都是用来检查线程是否持有锁的方法,不同之处在于 getHoldCount() 用来查询当前线程持有锁的数量,对于每个未通过解锁操作匹配的锁定操作,线程都会保持锁定状态,这个方法也通常用于调试和测试,例如

private ReentrantLock lock = new ReentrantLock();

public void lock(){
  assert lock.getHoldCount() == 0;
  lock.lock();
  try {
    // 执行业务代码
  }finally {
    lock.unlock();
  }
}

这个方法会返回当前线程持有锁的次数,如果当前线程没有持有锁,则返回0。

newCondition 创建 ConditionObject 对象

ReentrantLock 可以通过 newCondition 方法创建 ConditionObject 对象,而 ConditionObject 实现了 Condition  接口,关于 Condition 的用法我们后面再讲。

isLocked 判断是否锁定

查询是否有任意线程已经获取锁,这个方法用来监视系统状态,而不是用来同步控制,很简单,直接判断 state 是否等于0。

isFair 判断是否是公平锁的实例

这个方法也比较简单,直接使用 instanceof 判断是不是 FairSync 内部类的实例

public final boolean isFair() {
  return sync instanceof FairSync;
}

getOwner 判断锁拥有者

判断同步状态是否为0,如果是0,则没有线程拥有锁,如果不是0,直接返回获取锁的线程。

final Thread getOwner() {
  return getState() == 0 ? null : getExclusiveOwnerThread();
}

hasQueuedThreads 是否有等待线程

判断是否有线程正在等待获取锁,如果头节点与尾节点不相等,说明有等待获取锁的线程。

public final boolean hasQueuedThreads() {
  return head != tail;
}

isQueued 判断线程是否排队

判断给定的线程是否正在排队,如果正在排队,返回 true。这个方法会遍历队列,如果找到匹配的线程,返回true

public final boolean isQueued(Thread thread) {
  if (thread == null)
    throw new NullPointerException();
  for (Node p = tail; p != null; p = p.prev)
    if (p.thread == thread)
      return true;
  return false;
}

getQueueLength 获取队列长度

此方法会返回一个队列长度的估计值,该值只是一个估计值,因为在此方法遍历内部数据结构时,线程数可能会动态变化。 此方法设计用于监视系统状态,而不用于同步控制。

public final int getQueueLength() {
  int n = 0;
  for (Node p = tail; p != null; p = p.prev) {
    if (p.thread != null)
      ++n;
  }
  return n;
}

getQueuedThreads 获取排队线程

返回一个包含可能正在等待获取此锁的线程的集合。 因为实际的线程集在构造此结果时可能会动态更改,所以返回的集合只是一个大概的列表集合。 返回的集合的元素没有特定的顺序。

public final Collection<Thread> getQueuedThreads() {
  ArrayList<Thread> list = new ArrayList<Thread>();
  for (Node p = tail; p != null; p = p.prev) {
    Thread t = p.thread;
    if (t != null)
      list.add(t);
  }
  return list;
}

回答上面那个问题

那么你看完源码分析后,你能总结出 synchronized 和 lock 锁的实现 ReentrantLock 有什么异同吗?

Synchronzied 和 Lock 的主要区别如下:

  • 存在层面:Syncronized 是Java 中的一个关键字,存在于 JVM 层面,Lock 是 Java 中的一个接口

  • 锁的释放条件:1. 获取锁的线程执行完同步代码后,自动释放;2. 线程发生异常时,JVM会让线程释放锁;Lock 必须在 finally 关键字中释放锁,不然容易造成线程死锁

  • 锁的获取: 在 Syncronized 中,假设线程 A 获得锁,B 线程等待。如果 A 发生阻塞,那么 B 会一直等待。在 Lock 中,会分情况而定,Lock 中有尝试获取锁的方法,如果尝试获取到锁,则不用一直等待

  • 锁的状态:Synchronized 无法判断锁的状态,Lock 则可以判断

  • 锁的类型:Synchronized 是可重入,不可中断,非公平锁;Lock 锁则是 可重入,可判断,可公平锁

  • 锁的性能:Synchronized 适用于少量同步的情况下,性能开销比较大。Lock 锁适用于大量同步阶段:

    Lock 锁可以提高多个线程进行读的效率(使用 readWriteLock)

  • 在竞争不是很激烈的情况下,Synchronized的性能要优于ReetrantLock,但是在资源竞争很激烈的情况下,Synchronized的性能会下降几十倍,但是ReetrantLock的性能能维持常态;

  • ReetrantLock 提供了多样化的同步,比如有时间限制的同步,可以被Interrupt的同步(synchronized的同步是不能Interrupt的)等

还有什么要说的吗

面试官可能还会问你 ReentrantLock 的加锁流程是怎样的,其实如果你能把源码给他讲出来的话,一定是高分。如果你记不住源码流程的话可以记住下面这个简化版的加锁流程

  • 如果 lock 加锁设置成功,设置当前线程为独占锁的线程;

  • 如果 lock 加锁设置失败,还会再尝试获取一次锁数量,

    如果锁数量为0,再基于 CAS 尝试将 state(锁数量)从0设置为1一次,如果设置成功,设置当前线程为独占锁的线程;

    如果锁数量不为0或者上边的尝试又失败了,查看当前线程是不是已经是独占锁的线程了,如果是,则将当前的锁数量+1;如果不是,则将该线程封装在一个Node内,并加入到等待队列中去。等待被其前一个线程节点唤醒。

文章参考:

【试验局】ReentrantLock中非公平锁与公平锁的性能测试

第五章 ReentrantLock源码解析1--获得非公平锁与公平锁lock()

https://juejin.im/post/5c95df97e51d4551d06d8e8e

【JUC】JDK1.8源码分析之ReentrantLock(三)

https://www.lagou.com/lgeduarticle/73019.html

Linux双网卡设置IP属于同一网段的ping方法以及现象记录分析 文章目录前言ping以及MAC地址总结 前言 写在前面:经常遇到客户将板卡上的两个网络设备的IP地址设置为同一网段的情况,比如eth0:192.168.0.232,eth1:192.168.0.30. 我的解释是,不能设置为同一网段,或者使用其中一个时候下线另外一个网卡。但是我不知道这个说法到底是根据什么,查了很多资料也没找到明确的说法,但是下面这个实验能够说明一些现象的原因。 ping以及MAC地址 首先查看网卡的信息 ifconfig 因为两个网卡都在同一个网段,所以如果这个时候直接和我们的主机(I 阅读详情

相关推荐

PCIe Gen4 Switch芯片PM40028调试踩坑实录:从boot引脚设置到串口无输出的诡异问题

本文记录了PCIe Gen4 Switch芯片PM40028的实战调试过程,重点剖析了从boot引脚配置错误导致串口无输出,到使用逻辑分析仪定位并解决启动问题的完整排障思路。文章深入探讨了芯片启动流程、硬件信号测量方法,并总结了高速硬件调试的核心经验与系统性排查清单,为工程师解决类似PCIe Gen4设备调试难题提供实用指南。

i8j9k0l1的博客 253

isrun java用法_Java多线程问题--方法isFair()、isHeldByCurrentThread()和isLocked()的用法和区别...

本文内容部分引自《Java多线程编程核心技术》,感谢作者!!!代码地址:https://github.com/xianzhixianzhixian/thread.git方法isFair()、isHeldByCurrentThread()和isLocked()的用法和区别1、lock.isFair()方法用来判断lock锁是公平锁还是非公平锁。公平锁是指,线程获得锁的顺序是按其等待锁的先后顺序来的,...

weixin_42134234的博客 826

ABAQUS应用15——Abaqus软件中边界条件与力学中自由度的关系

核心关系:Abaqus通过约束自由度实现边界条件,自由度类型由单元决定。正确设置步骤:确定模型类型(实体/梁/壳)。识别节点的自由度(平动或转动)。根据实际约束施加对应的自由度限制。验证:通过检查变形模式、反力分布等确认边界条件合理性。正确理解自由度与边界条件的关系,是确保有限元模型准确模拟实际物理行为的关键。

George的博客 1546

redisson的isHeldByCurrentThread的使用解释

在thread-1还没有结束的时候,也就是在thread-1在获得锁但是还没有释放锁的时候, `thread-2由于被别的线程中断停止了等待从lock.tryLock的阻塞状态中返回继续执行接下来的逻辑,并且由于尝试去释放一个属于线程thread-1的锁而抛出了一个运行时异常导致该线程thread-2结束了, 然而thread-2完成了一系列操作后,线程thread-1才释放了自己的锁. 所以thread-2并没有获得锁,却执行了需要同步的内容,还尝试去释放锁。那解决方式我们就知道了,当前线程加的锁由当前线

京北游戏官方 9415

关于 Python PyQt5 界面运行时提示无法初始化Qt平台的解决方案

关于 Python PyQt5 界面运行时提示无法初始化Qt平台的解决方案

smart_num_1的博客 6884

UOS忘记密码别慌!用LiveCD工具5分钟搞定,附命令行救援模式详细步骤

本文详细介绍了UOS系统密码遗忘时的两种解决方案:图形化LiveCD工具和命令行救援模式。针对普通用户,LiveCD工具提供5分钟快速重置密码的便捷操作;而技术人员可通过命令行深度解析系统分区挂载与密码修改流程。文章还包含安全加固建议,帮助用户预防类似问题发生。

weixin_27032989的博客 592

Java多线程问题--方法isFair()、isHeldByCurrentThread()和isLocked()的用法和区别

本文内容部分引自《Java多线程编程核心技术》,感谢作者!!! 代码地址:https://github.com/xianzhixianzhixian/thread.git 方法isFair()、isHeldByCurrentThread()和isLocked()的用法和区别 1、lock.isFair()方法用来判断lock锁是公平锁还是非公平锁。公平锁是指,线程获得锁的顺序是按其等待锁...

樊先知樊先知的博客 1万+

UCIE Specification详解(三)

Protocol Layer(协议层)以及Die-to-Die Adapter

Crazzy_M的博客 1768

重入锁ReentrantLock常用方法(三)

1. isHeldByCurrentThread()    查询当前线程是否保持锁定。    isLocked()    查询是否存在任意线程保持此锁定。public class ReentrantLockMethodTest7 { private ReentrantLock lock = new ReentrantLock(); public void testMethod(...

Morgan_Xiang的专栏 2819

SAP项目中 Waterfall vs Agile 的深度对比分析背景:方法论的演进SAP项目实施方法论经历了显著的代际更替。早期以 ASAP(Accelerated SAP) 为代表,采用经典瀑

本文对比分析了SAP项目实施中瀑布模型(ASAP)与敏捷方法(SAP Activate)的核心差异。瀑布模型采用线性流程,需求固定但变更成本高;敏捷方法则通过迭代开发实现动态调整,强调最佳实践和用户持续参与。文章指出,SAP系统的复杂性使纯粹敏捷难以实施,需在标准化与定制化间取得平衡。最终建议根据项目特性选择方法论:稳定需求适用瀑布模型,变化频繁则推荐敏捷,而SAP Activate本质上是两者的结构化融合,代表未来趋势。关键在于匹配项目实际需求,而非盲目追随方法论潮流。

金牌架构师 345

使用 MATLAB/Simulink + Simscape Electrical + Simulink Design Optimization,构建一个沙漠环境中光伏组件灰尘积累与效率下降仿真模型

本文通过,构建了沙漠环境中光伏组件灰尘积累与效率下降仿真模型✅ 建立了风速-沙尘-积尘速率的物理关系✅ 仿真了灰尘积累过程及其对Isc 和 Pmax的影响✅ 量化分析了不同清洁策略的经济性✅ 提出了优化设计与智能运维建议。

xiaoheshang_123的博客 124

ReentrantLock 源码分析从入门到入土

回答一个问题 在开始本篇文章的内容讲述前,先来回答我一个问题,为什么 JDK 提供一个 synchronized 关键字之后还要提供一个 Lock 锁,这不是多此一举吗?难道 JDK 设计人员都是沙雕吗? 我听过一句话非常的经典,也是我认为是每个人都应该了解的一句话:你以为的并不是你以为的。明白什么意思么?不明白的话,加我微信我告诉你。 初识 ReentrantLock ReentrantLock...

程序员cxuan的个人主页 6158

【WorkBuddy专栏51】Codex与WorkBuddy的底层基因——两条完全不同的AI智能体路线(上)

【WorkBuddy专栏51】Codex与WorkBuddy的底层基因——两条完全不同的AI智能体路线(上)

AI人人懂 2195

并发情况如何实现加锁来保证数据一致性? | 京东云技术团队

ReentrantLock(可重入锁),指的是一个线程再次对已持有的锁保护的临界资源时,重入请求将会成功。:如果被请求的共享资源空闲,那么就当前请求资源的线程设置为有效的工作线程,将共享资源通过CAS设置为锁定状态;如果共享资源被占用,就采用一定的阻塞等待唤醒机制(CLH变体的FIFO双端队列)来保证锁分配。:无论是公平锁还是非公平锁的情况,加锁过程会利用一个state值。

京东科技开发者 1057

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

IEM模型,地表粗糙度模拟

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

JAVA并发多线程面试真题 2020最新最全丨来自阿里、百度、美团、京东多家大厂

写在前面 随着Java程序员的大幅增长和需求方对 Java 程序员提出更加严苛的选材标准,Java 程序员正面临着更加激烈的竞争。而在这其中,Java并发编程是一个优秀的开发者成长过程中绕不过去的挑战 在开发、测试以及调试多线程程序时存在着巨大的困难,因为并发性错误通常并不会以某种确定的方式显现出来。当这些错误出现时,通常是在最糟糕的时刻,例如在正式产品中,或者在高负载的情况下,当并发性错误被发现时,情况总是比较紧急甚至可以打倒整个项目团队,毁掉整个项目。 因此,Java并发与多线程就成了Ja..

weixin_48673251的博客 261

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

java lock 实例_Java并发编程 - 锁Lock取款机场景实例

转自:http://www.verejava.com/?id=17236703718463锁Lock取款机场景实例Lock是一个接口,ReentrantLock是它的实现类,下面通过“取款机案例”来剖析它的4个常用方法。1.爸爸妈妈同时在ATM上登录取款(不加任何锁)public classBank {private static double money = 10000;public voidl...

weixin_39581571的博客 249

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

谢飞机的Java大厂面试记:从HashMap到DDD的爆笑技术拷问

一篇以幽默故事形式讲解Java核心技术面试题的文章,涵盖JUC、JVM、Spring生态、中间件、数据库及架构设计等高频考点,附详细解析,助小白系统掌握面试重点。

sonicxia的博客 571

必拿下!字节跳动架构师熬夜一周整理的社招面经,看完直接手撕面试官

写在前面: 一面问得过于简单,二面,三面难度适中过于困难。整体的体验还行。。 字节一面 1.Java如何实现线程安全(synchronized,ReentrantLock,AtomicInteger,ThreadLocal,CAS) 2.CAS如何解决ABA问题(版本号) 3.AtomicInteger的原理(UnSafe类,底层是一句CPU指令,避免了并发问题) 4.可重入锁是什么,非可重入锁又是什么(略 5.代码,实现生产者和消费者,一个长度100的buffer,10个生产者线程,10个消费者线程 (我

weixin_53185946的博客 1342

拿下了!费时两个月成功拿下了字节offer,在这里分享一下我的四面面经吧

写在前面: 一面问得过于简单,二面,三面难度适中过于困难。整体的体验还行。。 字节一面 1.Java如何实现线程安全(synchronized,ReentrantLock,AtomicInteger,ThreadLocal,CAS) 2.CAS如何解决ABA问题(版本号) 3.AtomicInteger的原理(UnSafe类,底层是一句CPU指令,避免了并发问题) 4.可重入锁是什么,非可重入锁又是什么(略 5.代码,实现生产者和消费者,一个长度100的buffer,10个生产者线程,10个消费者线程 (我

weixin_49494194的博客 227

Java面试突击方案:高频考点驱动与场景题破局

在软件工程领域,面试准备是开发者职业发展中的关键环节,尤其对于Java技术栈而言。其核心原理在于通过结构化复习与针对性训练,将分散的知识点串联成体系化的解决方案。从技术价值看,这不仅关乎个人面试成功率,更是对知识掌握深度与应用能力的综合检验。典型的应用场景包括时间紧迫的求职冲刺、知识体系查漏补缺以及技术表达能力的强化训练。本文聚焦于Java面试的高效准备策略,通过高频考点驱动和场景题拆解框架,帮助开发者在有限时间内构建应对面试的核心能力,自然收敛到以实战输出为导向的复习方法论。

weixin_30888413的博客 343

Redission 对比isHeldByCurrentThread()和unlock()

既然都产生IO,unlock也包含isHeldByCurrentThread的功能,不如直接调用unlock,放弃isHeldByCurrentThread前置判断。

m178643的博客 345

Lock的使用(五)——使用ReentrantLock类

(3)方法void tryLock(long timeout,TimeUnit unit)的作用是:如果给定线程在等待时间内未被另一个线程保持,且当前线程未被中断,则获取该锁定。(1)方法void lockInterruptibly()的作用是:如果当前线程未被中断,则获取锁定(需要等待别的线程释放锁才行),如果已被中断则出现异常。该实验使用的是Lock()方法,说明线程B被interrupt中断了,那么执行lock()则不出现异常,正常执行。在默认的情况下,ReentrantLock类使用的是非公平锁。

qq_44307209的博客 492

SET key value [EX seconds] [PX milliseconds] [NX|XX]

Setkeyto hold the stringvalue. Ifkeyalready holds a value, it is overwritten, regardless of its type. Any previous time to live associated with the key is discarded on succ...

weixin_34007879的博客 1597

多线程编程第四章Lock的使用

使用ReentrantLock lock.lock();//此方法相当于上锁 lock.unlock();//此方法相当于释放锁 Condition condition = lock.newCondition(); condition.await();//相当于wait() condition.signal();//相当于nontify condition.signalAll();//相当于no...

孤竹彧的根据地 1523
上一篇: 如何短时间内通过Java面试?
下一篇: 极简入门,Shiro的认证与授权流程解析
Java思维导图
博客等级 码龄10年 306粉丝 71原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值