深入浅出Java并发包—锁机制(一)

VSCode连接SAP ABAP开发环境 本文介绍了使用VSCode连接ABAP开发环境的详细步骤。首先通过SICF或SMICM事务码获取ABAP连接地址,然后安装ABAP remote filesystem插件。提供了两种创建连接的方法:通过命令面板逐步配置(输入服务器地址、账号、系统标识等)或直接编辑JSON配置文件。最后通过命令面板选择已创建的连接即可完成连接,连接成功后可在VSCode左侧工作区查看ABAP系统内容进行开发。JSON配置方式更为简便推荐。整个流程帮助开发者摆脱复杂的Eclipse配置,实现快速便捷的ABAP开发环境搭建。 阅读详情

转自:http://yhjhappy234.blog.163.com/blog/static/316328322013548580299/

前面我们看到了Lock和synchronized都能正常的保证数据的一致性(上文例子中执行的结果都是20000000),也看到了Lock的优势,那究竟他们是什么原理来保障的呢?今天我们就来探讨下Java中的锁机制!

Synchronized是基于JVM来保证数据同步的,而Lock则是在硬件层面,依赖特殊的CPU指令实现数据同步的,那究竟是如何来实现的呢?我们一一看来!

一、synchronized的实现方案

synchronized比较简单,语义也比较明确,尽管Lock推出后性能有较大提升,但是基于其使用简单,语义清晰明了,使用还是比较广泛的,其应用层的含义是把任意一个非NULL的对象当作锁。当synchronized作用于方法时,锁住的是对象的实例(this),当作用于静态方法时,锁住的是Class实例,又因为Class的相关数据存储在永久带,因此静态方法锁相当于类的一个全局锁,当synchronized作用于一个对象实例时,锁住的是对应的代码块。在Sun的HotSpot JVM实现中,其实synchronized锁还有一个名字:对象监视器。

当多个线程一起访问某个对象监视器的时候,对象监视器会将这些请求存储在不同的容器中。

1、  Contention List:竞争队列,所有请求锁的线程首先被放在这个竞争队列中

2、  Entry List:Contention List中那些有资格成为候选资源的线程被移动到Entry List中

3、  Wait Set:哪些调用wait方法被阻塞的线程被放置在这里

4、  OnDeck:任意时刻,最多只有一个线程正在竞争锁资源,该线程被成为OnDeck

5、  Owner:当前已经获取到所资源的线程被称为Owner

6、  !Owner:当前释放锁的线程

下图展示了他们之前的关系

深入浅出Java并发包—锁机制(一) - 一线天色 天宇星辰 - 一线天色 天宇星辰

 ContentionList

并不是真正意义上的一个队列。仅仅是一个虚拟队列,它只有 Node 以及对应的 Next 指针构成,并没有 Queue 的数据结构。每次新加入 Node 会在队头进行,通过 CAS 改变第一个节点为新增节点,同时新增阶段的 next 指向后续节点,而取数据都在队列尾部进行。

深入浅出Java并发包—锁机制(一) - 一线天色 天宇星辰 - 一线天色 天宇星辰

 JVM

每次从队列的尾部取出一个数据用于锁竞争候选者( OnDeck ),但是并发情况下, ContentionList 会被大量的并发线程进行 CAS 访问,为了降低对尾部元素的竞争, JVM 会将一部分线程移动到 EntryList 中作为候选竞争线程。 Owner 线程会在 unlock 时,将 ContentionList 中的部分线程迁移到 EntryList 中,并指定 EntryList 中的某个线程为 OnDeck 线程(一般是最先进去的那个线程)。 Owner 线程并不直接把锁传递给 OnDeck 线程,而是把锁竞争的权利交个 OnDeck , OnDeck 需要重新竞争锁。这样虽然牺牲了一些公平性,但是能极大的提升系统的吞吐量,在 JVM 中,也把这种选择行为称之为“竞争切换”。

OnDeck线程获取到锁资源后会变为Owner线程,而没有得到锁资源的仍然停留在EntryList中。如果Owner线程被wait方法阻塞,则转移到WaitSet队列中,直到某个时刻通过notify或者notifyAll唤醒,会重新进去EntryList中。

处于ContentionList、EntryList、WaitSet中的线程都处于阻塞状态,该阻塞是由操作系统来完成的(Linux内核下采用pthread_mutex_lock内核函数实现的)。该线程被阻塞后则进入内核调度状态,会导致系统在用户和内核之间进行来回切换,严重影响锁的性能。为了缓解上述性能问题,JVM引入了自旋锁。原理非常简单,如果Owner线程能在很短时间内释放锁资源,那么哪些等待竞争锁的线程可以稍微等一等(自旋)而不是立即阻塞,当Owner线程释放锁后可立即获取锁,进而避免用户线程和内核的切换。但是Owner可能执行的时间会超过设定的阈值,争用线程在一定时间内还是获取不到锁,这是争用线程会停止自旋进入阻塞状态。基本思路就是先自旋等待一段时间看能否成功获取,如果不成功再执行阻塞,尽可能的减少阻塞的可能性,这对于占用锁时间比较短的代码块来说性能能大幅度的提升!

但是有个头大的问题,何为自旋?其实就是执行几个空方法,稍微等一等,也许是一段时间的循环,也许是几行空的汇编指令,其目的是为了占着CPU的资源不释放,等到获取到锁立即进行处理。但是如何去选择自旋的执行时间呢?如果自旋执行时间太长,会有大量的线程处于自旋状态占用CPU资源,进而会影响整体系统的性能。因此自旋的周期选的额外重要!

JVM对于自旋周期的选择,基本认为一个线程上下文切换的时间是最佳的一个时间,同时JVM还针对当前CPU的负荷情况做了较多的优化

1、  如果平均负载小于CPUs则一直自旋

2、  如果有超过(CPUs/2)个线程正在自旋,则后来线程直接阻塞

3、  如果正在自旋的线程发现Owner发生了变化则延迟自旋时间(自旋计数)或进入阻塞

4、  如果CPU处于节电模式则停止自旋

5、  自旋时间的最坏情况是CPU的存储延迟(CPU A存储了一个数据,到CPU B得知这个数据直接的时间差)

6、  自旋时会适当放弃线程优先级之间的差异

Synchronized在线程进入ContentionList时,等待的线程就通过自旋先获取锁,如果获取不到就进入ContentionList,这明显对于已经进入队列的线程是不公平的,还有一个不公平的事情就是自旋获取锁的线程还可能直接抢占OnDeck线程的锁资源。

在JVM6以后还引入了一种偏向锁,主要用于解决无竞争下面锁的性能问题。我们首先来看没有这个会有什么样子的问题。

现在基本上所有的锁都是可重入的,即已经获取锁的线程可以多次锁定/解锁监视对象,但是按照之前JVM的设计,每次加锁解锁都采用CAS操作,而CAS会引发本地延迟(下面会讲原因),因此偏向锁希望线程一旦获取到监视对象后,之后让监视对象偏向这个锁,进而避免多次CAS操作,说白了就是设置了一个变量,发现是这个线程过来的就避免再走加锁解锁流程。

那CAS为什么会引发本地延迟呢?这要从多核处(SMP)理架构说起(前面有提到过--JVM内存模型),下图基本上表明了多核处理的架构

深入浅出Java并发包—锁机制(一) - 一线天色 天宇星辰 - 一线天色 天宇星辰

 多核

CPU 会共享一条系统总线,靠总线和主存通讯,但是每个 CPU 又有自己的一级缓存,而 CAS 是一条原子指令,其作用是让 CPU 比较,如果相同则进行数据更新,而这些是基于硬件实现的( JVM 只是封装了硬件的汇编调用, AtomicInteger 其实是通过调用这些封装后的接口实现的)。多核运算时,由于线程切换,很有可能第二次取值是在另外一核 CPU 上执行的。假设 Core1 和 Core2 把对应的某个值加载到自己的一级缓存时,某个时刻, core1 更新了这个数据并通过总线通知主存,此时 core2 的一级缓存中的数据就失效了,他需要从主存中重新加载一次到一级缓存中,大家通过总线通讯被称之为一致性流量,总线的通讯能力有限,当缓存一致性流量过大时,总线会成为瓶颈,而当 Core1 和 Core2 的数据再次一致时,被称为缓存一致性!

而CAS要保证数据的一致性,恰好会引发比较多的一致性流量,如果有很多线程共享一个对象,当某个线程成功执行一次CAS时会引发总线风暴,这就是本地延迟,而偏向锁就是为了消除CAS,降低Cache一致性流量!

当然并不是所有的CAS都会引发总线风暴,这和Cache一致性协议有关系的。但是偏向锁的引入却带来了另外一个问题,在很多线程竞争使用中,如果一个线程持有偏向锁,另外一个线程想争用偏向对象,拥有者想释放这个偏向锁,释放会带来额外的性能开销,但是总体来说偏向锁带来的好处还是大于CAS的代价的。

 

二、Lock的实现

与synchronized不同的是,Lock书纯Java实现的,与底层的JVM无关。在java.util.concurrent.locks包中有很多Lock的实现类,常用的有ReentrantLock、ReadWriteLock(实现类ReentrantReadWriteLock),其实现都依赖java.util.concurrent.AbstractQueuedSynchronizer类(简称AQS),实现思路都大同小异,因此我们以ReentrantLock作为讲解切入点。

分析之前我们先来花点时间看下AQS。AQS是我们后面将要提到的CountDownLatch/FutureTask/ReentrantLock/RenntrantReadWriteLock/Semaphore的基础,因此AQS也是Lock和Excutor实现的基础。它的基本思想就是一个同步器,支持获取锁和释放锁两个操作。

获取锁:首先判断当前状态是否允许获取锁,如果是就获取锁,否则就阻塞操作或者获取失败,也就是说如果是独占锁就可能阻塞,如果是共享锁就可能失败。另外如果是阻塞线程,那么线程就需要进入阻塞队列。当状态位允许获取锁时就修改状态,并且如果进了队列就从队列中移除。

while(synchronization state does not allow acquire){

    enqueue current thread if not already queued;

    possibly block current thread;

}

dequeue current thread if it was queued;

释放锁:这个过程就是修改状态位,如果有线程因为状态位阻塞的话,就唤醒队列中的一个或者更多线程。

update synchronization state;

if(state may permit a blocked thread to acquire)

    unlock one or more queued threads;

要支持上面两个操作就必须有下面的条件:

1、  状态位必须是原子操作的

2、  阻塞和唤醒线程

3、  一个有序的队列,用于支持锁的公平性

怎么样才能满足这几个条件呢?

1、  原子操作状态位,前面我们已经提到了,实际JDK中也是通过一个32bit的整数位进行CAS操作来实现的。

2、  阻塞和唤醒,JDK1.5之前的API中并没有阻塞一个线程,然后在将来的某个时刻唤醒它(wait/notify是基于synchronized下才生效的,在这里不算),JDK5之后利用JNI在LockSupport 这个类中实现了相关的特性!

深入浅出Java并发包—锁机制(一) - 一线天色 天宇星辰 - 一线天色 天宇星辰

 

3、  有序队列:在AQS中采用CLH队列来解决队列的有序问题。

我们来看下ReentrantLock的调用过程

经过源码分析,我们看到ReentrantLock把所有的Lock都委托给Sync类进行处理,该类继承自AQS,其类关系图如下

深入浅出Java并发包—锁机制(一) - 一线天色 天宇星辰 - 一线天色 天宇星辰

 其中

Sync 又有两个 final static 的子类 NonfairSync 和 FairSync 用于支持非公平锁和公平锁。我们先来挑一个看下对应 Reentrant.lock() 的调用过程(默认为非公平锁)

深入浅出Java并发包—锁机制(一) - 一线天色 天宇星辰 - 一线天色 天宇星辰

 这些模版很难让我们直观的看到整个调用过程,但是通过上面的过程图和

AbstractQueuedSynchronizer 的注释可以看出, AbstractQueuedSynchronizer 抽象了大多数 Lock 的功能,而只把 tryAcquire(int) 委托给子类进行多态实现。 tryAcquire 用于判断对应线程事都能够获取锁,无论成功与否, AbstractQueuedSynchronizer 都将处理后面的流程。

简单来讲,AQS会把所有请求锁的线程组成一个CLH的队列,当一个线程执行完毕释放锁(Lock.unlock())的时候,AQS会激活其后继节点,正在执行的线程不在队列当中,而那些等待的线程全部处于阻塞状态,经过源码分析,我们可以清楚的看到最终是通过LockSupport.park()实现的,而底层是调用sun.misc.Unsafe.park()本地方法,再进一步,HotSpot在Linux中中通过调用pthread_mutex_lock函数把线程交给系统内核进行阻塞。其运行示意图如下

深入浅出Java并发包—锁机制(一) - 一线天色 天宇星辰 - 一线天色 天宇星辰

 与

synchronized 相同的是,这个也是一个虚拟队列,并不存在真正的队列示例,仅存在节点之前的前后关系。(注:原生的 CLH 队列用于自旋锁, JUC 将其改造为阻塞锁)。和 synchronized 还有一点相同的是,就是当获取锁失败的时候,不是立即进行阻塞,而是先自旋一段时间看是否能获取锁,这对那些已经在阻塞队列里面的线程显然不公平(非公平锁的实现,公平锁通过有序队列强制线程顺序进行),但会极大的提升吞吐量。如果自旋还是获取失败了,则创建一个节点加入队列尾部,加入方法仍采用 CAS 操作,并发对队尾 CAS 操作有可能会发生失败, AQS 是采用自旋循环的方法,知道 CAS 成功!下面我们来看下锁的实现细节!

锁的实现依赖与lock()方法,Lock()方法首先是调用acquire(int)方法,不管是公平锁还是非公平锁

public final void acquire(int arg) {

         if (!tryAcquire(arg) &&

             acquireQueued(addWaiter(Node.EXCLUSIVE), arg))

             selfInterrupt();

     }

Acquire()方法默认首先调用tryAcquire(int)方法,而此时公平锁和不公平锁的实现就不一样了。

1、Sync.NonfairSync.TryAcquire(非公平锁)

nonfairTryAcquire方法是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;

    }

该方法首先会判断当前线程的状态,如果c==0 说明没有线程正在竞争锁。(反过来,如果c!=0则说明已经有其他线程已经拥有了锁)。如果c==0,则通过CAS将状态设置为acquires(独占锁的acquires为1),后续每次重入该锁都会+1,每次unlock都会-1,当数据为0时则释放锁资源。其中精妙的部分在于:并发访问时,有可能多个线程同时检测到c为0,此时执行compareAndSetState(0, acquires))设置,可以预见,如果当前线程CAS成功,则其他线程都不会再成功,也就默认当前线程获取了锁,直接作为running线程,很显然这个线程并没有进入等待队列。如果c!=0,首先判断获取锁的线程是不是当前线程,如果是当前线程,则表明为锁重入,继续+1,修改state的状态,此时并没有锁竞争,也非CAS,因此这段代码也非常漂亮的实现了偏向锁。

深入解析FPGA中的GTX高速收发器架构与设计原理 本文深入解析了FPGA中GTX高速收发器的核心架构与设计原理。文章将GTX比作数据“高速公路”,详细拆解了其PMA(物理媒介适配层)与PCS(物理编码子层)的双层结构,阐述了串并转换、时钟恢复等关键技术,并提供了时钟源选型(QPLL/CPLL)、上电复位流程及信号完整性调试等实战指南,是掌握高速接口设计的必备知识。 阅读详情

相关推荐

Rasa Core开发指南

文章目录1. Rasa Core简介1.1 Rasa Core消息处理流程1.2 安装Rasa Core2. Dialogue模型训练2.1 Story样本数据2.2 Domain2.2.0 intents2.2.1 actions2.2.2 templates2.2.3 entities2.2.4 slots3 .训练和使用对话模型3.1 训练对话模型3.2 使用对话模型4. 搭建CustomA...

老蒋也疯狂 1万+

重回synchronized(源码解读与实战解析篇)

以下获取和释放流程皆出自源码

Liyizhi111的博客 1069

Windows 必看!OpenClaw 一键安装教程|告别报错,一次成功不踩坑

OpenClaw 完整安装与配置的全流程教程

m0_70389289的博客 1085

autoreleasePool与Runloop

https://www.jianshu.com/p/0e8af0a0b4ce 一:autorelease对象的释放时机 @autoreleasepool即自动释放池,在自动释放池中声明的对象如果调用了autorelase方法,那么当@autoreleasepool代码块执行完之后,在块中调用过autorelease方法的对象都会自动调用一次release方法。 转换为C++代码 int main(int argc, const char * argv[]) { /* @autoreleasepoo

qq_44865905的博客 1372

智慧楼宇解决方案-全套大合集

智慧楼宇解决方案,楼宇能耗-环境-设备统一管控解决方案。

byte58的博客 2592

基于ESP32-WROOM的智能蓝牙电压电流监测与远程控制系统设计

本文介绍了基于ESP32-WROOM的智能蓝牙电压电流监测与远程控制系统设计。该系统集成了INA219传感器和OLED显示屏,通过蓝牙实现无线数据传输和远程控制,适用于智能家居能耗监控和工业设备管理,具有成本低、精度高、功耗优化等优点。

qsc901234的博客 203

三大队列cxq,entrylist,waitset 个人理解分析

1.synchronized,wait(),notify()方法等这些功能底层怎么实现的呢? 其实就是操控cxq,entrylist,waitset这三大队列从而实现的。所以有必要好好的梳理下 entrylist 是双向链表 2.synchronized 重锁的时候,进行抢锁的流程怎么样的呢? 大家都知道重量级锁就是各个线程通过cas去修改ObjectMonitor中ower字段,谁修改成功表示谁抢到锁了,如果失败了会cas加入cxq中,cxq是栈结构。 3.wait()方法会使得当前的线程进

杨坤的博客 7708

Cadence Virtuoso实战:3分钟搞定反相器参数化设计(附CDF配置避坑指南)

本文详细介绍了如何在Cadence Virtuoso中利用CDF参数传递功能实现反相器的参数化设计,包括PMOS和NMOS的基础搭建、CDF配置技巧及常见报错解决方案。通过实战案例和避坑指南,帮助工程师快速掌握高效设计方法,提升集成电路设计效率。

weixin_28292761的博客 337

Java高并发程序设计学习笔记(二)锁相关

锁的种类 Java中的锁大致分为:偏向锁,自旋锁,轻量级锁,重量级锁 锁的使用方式为:先提供偏向锁,如果不满足时,升级为轻量级锁,再不满足,升级为重量级锁。自旋锁是一个过渡的锁状态,不是一种实际的锁类型。锁只能升级,不能降级。 偏向锁 是一种编译解释锁。如果代码中不可能出现多线程并发争抢同一个锁的时候,JVM编译代码,解释执行的时候,会自动的放弃同步信息。消除synchronized...

qq_16694993的博客 486

TJA1445/TJA1465 CAN收发器硬件设计与软件配置实战指南

控制器局域网(CAN)总线是汽车电子和工业控制领域实现电子控制单元(ECU)间可靠通信的核心技术。其工作原理是将数字信号转换为差分信号进行抗干扰传输,技术价值在于构建稳定、高效的分布式实时控制系统。随着汽车电子架构向域集中式演进,对CAN总线的通信速率、网络复杂度和静态功耗提出了更高要求,这催生了支持CAN FD协议和智能电源管理的新一代高速CAN收发器。在车载网关、域控制器及工业网络节点等应用场景中,NXP的TJA1445和TJA1465系列收发器凭借其部分组网(Partial Networking)和选

weixin_29655587的博客 411

ZYNQ系列PS侧和PL侧DDR3或DDR4在AD(Altium Designer 25)中的layout布线规则约束

DDR3或DDR4的PCB布线规则通常有相对固定的要求,对应的,在PCB设计时有固定的约束设置。

FPGA艺术家的博客 790

java中的锁(二)

本章主要深入讲解synchronized关键字。 一、synchronized关键字的使用 synchronized关键字是JVM层面实现的锁,常见的使用方式有: 修饰实例方法,作用于当前实例加锁,进入同步代码前要获得当前实例的锁。 修饰静态方法,作用于当前类对象加锁,进入同步代码前要获得当前类对象的锁。 修饰代码块,指定加锁对象,对给定对象加锁,进入同步代码库前要获...

西木风落 539

YOLOv5 实现 10 种热力图可视化方式教程 | GradCAM XGradCAM ScoreCAM LayerCAM HiResCAM EigenCAM......

10 种热力图可视化方法 ,总有一款适合你

Coding... 5569

java 并发包 锁_深入浅出Java并发包—锁机制(二)

2、Sync.FairSync.TryAcquire(公平锁)我们直接来看代码protected final boolean tryAcquire(intacquires) {final Thread current =Thread.currentThread();int c =getState();if (c == 0) {if (isFirst(current) &&compa...

weixin_34364310的博客 153

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

《深入浅出 Java Concurrency》—锁机制(一)Lock与ReentrantLock

<br /><br />转自:http://www.blogjava.net/xylz/archive/2010/07/05/325274.html<br />前面的章节主要谈谈原子操作,至于与原子操作一些相关的问题或者说陷阱就放到最后的总结篇来整体说明。从这一章开始花少量的篇幅谈谈锁机制。<br />上一个章节 中谈到了锁机制,并且针对于原子操作谈了一些相关的概念和设计思想。接下来的文章中,尽可能的深入研究锁机制,并且理解里面的原理和实际应用场合。<br />尽管synchronized在语法上已经足够

FG2006的专栏 1万+

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

深入浅出Java并发包—锁机制(二)

接上文《深入浅出Java并发包—锁机制(一)》 2、Sync.FairSync.TryAcquire(公平锁) 我们直接来看代码 protected final boolean tryAcquire(int acquires) { final Thread current = Thread.currentThread(); int ...

weixin_30376163的博客 92

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

深入浅出Java锁机制:从synchronized到StampedLock

在多线程并发编程中,锁机制是保障线程安全的核心手段。本文将系统解析Java中各类锁的实现原理与应用场景,助你彻底掌握高并发环境下的数据同步策略。

weixin_52008495的博客 549

深入浅出Java并发包—锁机制

http://www.cnblogs.com/longshiyVip/p/5213771.html http://www.cnblogs.com/longshiyVip/p/5211490.html http://www.cnblogs.com/longshiyVip/p/5213812.html 前面我们看到了Lock和synchronized都能正常的保证数据的一

气自华 445

《深入浅出 Java Concurrency》—锁机制(二) AQS

在理解J.U.C原理以及锁机制之前,我们来介绍J.U.C框架最核心也是最复杂的一个基础类:java.util.concurrent.locks.AbstractQueuedSynchronizer 。AQSAbstractQueuedSynchronizer,简称AQS,是J.U.C最复杂的一个类,导致绝大多数讲解并发原理或者实战的时候都不会提到此类。但是虚心的作者愿意借助自己有限的能力和精力来探讨一二(参考资源中也有一些作者做了部分的分析。)。首先从理论知识开始,在了解了相关原理后会针对源码进行一些分析

FG2006的专栏 5666

深入浅出Java并发包—锁机制(三)

接上文《深入浅出Java并发包—锁机制(二)》 由锁衍生的下一个对象是条件变量,这个对象的存在很大程度上是为了解决Object.wait/notify/notifyAll难以使用的问题。 条件(也称为条件队列或条件变量)为线程提供了一个含义,以便在某个状态条件现在可能为true的另一个线程通知它之前,一直挂起该线程(即让其“等待”)。因为访问此共享状态信息发生在不同的线程中,所以它...

weixin_30763397的博客 72

深入浅出Java并发包—锁机制(转)

前面我们看到了Lock和synchronized都能正常的保证数据的一致性(上文例子中执行的结果都是20000000),也看到了Lock的优势,那究竟他们是什么原理来保障的呢?今天我们就来探讨下Java中的锁机制! Synchronized是基于JVM来保证数据同步的,而Lock则是在硬件层面,依赖特殊的CPU指令实现数据同步的,那究竟是如何来实现的呢?我们一一看来! 一、synchroni...

feiyeguohai1的博客 332

深入理解Java中的锁机制

锁机制在并发编程中非常关键,它帮助我们解决资源共享和线程安全的问题。记住,合理使用锁非常重要,过度使用或不当使用锁可能会导致性能问题甚至死锁。小黑希望通过这篇文章,咱们能对Java中的锁有一个全面的了解。不论是内部锁(synchronized)还是显式锁(如ReentrantLock),它们都有自己的使用场景和优缺点。最关键的是,咱们要根据实际情况选择合适的锁类型和策略。学习并发编程是一个不断实践和探索的过程。

宋小黑的博客 1125

《深入浅出Java并发编程从锁机制到CompletableFuture的异步实践》

synchronized通过monitor实现线程互斥,而ReentrantLock提供了更灵活的锁操作,支持可中断锁、尝试获取锁和公平锁等特性。这种模式显著提高了系统吞吐量和资源利用率。早期开发者主要依赖基础的锁机制解决资源竞争问题,随着业务复杂度的提升,JDK不断引入更强大的工具类,最终在JDK 8中推出的CompletableFuture实现了真正意义上的声明式异步编程。CompletableFuture与虚拟线程结合后,将能够以更低的资源消耗处理大量并发任务,为Java并发编程开启新的可能性。

u010646006的博客 399
上一篇: 文本操作的底层
下一篇: ReentrantLock解析
wingahi
博客等级 码龄15年 15粉丝 43原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值