一文搞懂synchronized锁的升级过程

简介: synchronized锁的升级过程包括偏向锁、轻量锁和重量级锁。偏向锁在无竞争时可重复使用,轻量锁通过CAS自旋实现多线程竞争,重量级锁则会导致线程阻塞,涉及用户态到内核态的切换。CAS(比较并交换)用于实现乐观锁,保证原子性操作,但可能引发CPU资源浪费。文中还展示了手写锁的升级实现代码。

synchronized锁的升级过程

1. 偏向锁→轻量锁(cas自旋)→重量级锁

偏向锁:  同一个线程在没有其他线程竞争锁的情况下,可以一直复用我们的锁,不会重复获取锁。

轻量锁:  多个线程同时获取锁,只有一个线程获取锁,没有获取到锁的线程会通过CAS不断重试

重量级锁: 重试多次如果没有获取到锁,则当前线程会变成阻塞,由用户态切换到内核态。

   在使用synchronized1.0版本 如果没有获取到锁的情况下则当前线程直接会变为阻塞的状态。升级为重量级锁,在后期唤醒的成本会非常高。升级为重量级锁则需要从用户态切换到内核态。

用户态与内核态区别

1、内核态(Kernel Mode):运行操作系统程序,操作硬件  (内核空间)

2、用户态(User Mode):运行用户程序(用户空间)

     为了安全应用程序无法直接调用的硬件的功能,而是将这些功能封装成特定的函数。当应用程序需要硬件功能时(例如读写文件),就需要进行系统调用。当进程进行系统调用后就从用户态装换为内核态。

什么是CAS

CAS: Compare and Swap,翻译成比较并交换。 执行函数CASVE,N

CAS3个操作数,内存值V,旧的预期值E,要修改的新值N。当且仅当预期值E和内存值V相同时,将内存值V修改为N,否则什么都不做。

保证线程安全性的问题原子性

(V,E,N)===乐观锁

V: 全局共享变量  原子类中 value===0

E: 旧的预期值

N: 修改的新值

CAS:无锁(自旋控制乐观锁)

缺点:自旋会消耗的cpu的资源 cas自旋空转会引发 cpu飙高,可通过短暂线程sleep的方式解决由自旋生成的cpu飙高的问题。

底层基于unsafe类实现

手写锁的升级过程

/**
     * recursions+1  获取锁成功 当前线程重入+1
     */
    public void lock() {
        if(recursions==0){
            return;
        }
        // 如果当前线程已经获取到锁的话,则不需要重复获取锁 直接复用
        if (ownerLockThread == Thread.currentThread()) {
            // 锁的重入次数+1
            recursions++;
            return;
        }
        /**
         * 两个线程同时执行 cas 操作 将锁的状态从0改成===11
         * 最终只有一个线程修改成功 自旋
         */
        /**
         * 每个线程 获取锁重试次数
         * ------不是重入 而是 重试
         *
         */
        int spinCount = 0;
        for (; ; ) {
            if (spinCount >= 3) {
                // 让我们当前线程变为阻塞状态
                notLockThreads.offer(Thread.currentThread());
                // 重量锁
                LockSupport.park();
                // 需要我们重试次数归0
                spinCount = 0;
            }
            // 优化代码 当前线程如果已经获取到锁 则直接复用
            if (lockState.compareAndSet(0, 1)) {
                // 当前线程获取锁成功
                ownerLockThread = Thread.currentThread();
                // 锁的重入次数+1 recursions==1
                recursions++;
                return;
            }
            spinCount++;
        }
    }

相关文章
|
5月前
|
存储 缓存 安全
synchronized 锁升级全流程
本文深入解析Java中synchronized的锁升级机制,基于JDK17版本详细介绍了从无锁、偏向锁、轻量级锁到重量级锁的完整升级流程。文章通过对象头MarkWord的结构分析、JVM源码解读和实战代码验证,全面阐述了不同锁状态的特点、适用场景和性能差异,并澄清了常见误区。同时提供了生产环境的最佳实践建议,包括锁粒度优化、JVM参数配置和死锁规避策略,帮助开发者深入理解并发编程核心机制,提升多线程程序性能。
599 1
|
存储 关系型数据库 数据库
聊多版本并发控制(MVCC)
MVCC是数据库并发控制技术,用于减少读写冲突。它维护数据的多个版本,使事务能读旧数据而写新数据,无需锁定记录。当前读获取最新版本,加锁防止修改;快照读不加锁,根据读取时的读视图(readview)决定读哪个版本。InnoDB通过隐藏字段(DB_TRX_ID, DB_ROLL_PTR)和undo log存储版本,readview记录活跃事务ID。读已提交每次读取都创建新视图,可重复读则在整个事务中复用一个视图,确保一致性。MVCC通过undo log版本链和readview规则决定事务可见性,实现了非阻塞并发读。
1944 5
聊多版本并发控制(MVCC)
|
缓存 Java 应用服务中间件
Tomcat是如何打破"双亲委派"机制的?
上文我们详细了解了类加载以及什么是双亲委派机制,相信很多童鞋都了解Tomcat打破了双亲委派机制,本文将对Tomcat为什么要打破双亲委派机制,以及Tomcat是如何打破双亲委派机制的,进行完整性的复盘与解析。
4233 0
Tomcat是如何打破"双亲委派"机制的?
|
5月前
|
存储 缓存 安全
synchronized 底层全解:从对象头、锁升级到内核实现,击穿并发编程的核心基石
本文深度剖析Java中synchronized的底层原理:从三种使用范式、字节码实现,到对象内存布局、Mark Word状态切换,详解锁升级(偏向→轻量→重量)全流程及JVM优化(锁消除/粗化),并结合JOL实战验证,兼顾理论深度与生产实用性。
628 2
|
存储 安全 Java
synchronized 锁升级
JDK 6 引入的 synchronized 锁升级机制,通过偏向锁、轻量级锁和重量级锁的动态切换,优化了多线程同步性能。该机制根据竞争情况逐步升级锁状态,减少线程阻塞和系统调用开销,从而提升并发效率。
562 0
|
5月前
|
缓存 监控 算法
吃透 JVM 内存管理与调优:从底层原理到生产级落地实战(JDK17 专属)
本文深入解析JDK17 JVM内存管理与调优。首先剖析JVM内存模型核心架构,包括线程私有区域(程序计数器、虚拟机栈、本地方法栈)和共享区域(堆、元空间等)。通过可复现代码示例演示栈溢出、堆OOM等异常场景,并介绍jstat、jstack等排查工具。详细讲解垃圾回收算法(标记-清除、复制、整理)及JDK17主流收集器(G1、ZGC等)的适用场景。重点阐述生产级调优全流程:从监控定位问题到参数优化,提供常见问题排查方案和参数配置最佳实践。
675 6
|
存储 安全 Java
ThreadLocal - 原理与应用场景详解
ThreadLocal是Java中用于实现线程隔离的重要工具,为每个线程提供独立的变量副本,避免多线程数据共享带来的安全问题。其核心原理是通过 ThreadLocalMap 实现键值对存储,每个线程维护自己的存储空间。ThreadLocal 广泛应用于线程隔离、跨层数据传递、复杂调用链路的全局参数传递及数据库连接管理等场景。此外,InheritableThreadLocal 支持子线程继承父线程的变量值,而 TransmittableThreadLocal 则解决了线程池中变量传递的问题,提升了多线程上下文管理的可靠性。深入理解这些机制,有助于开发者更好地解决多线程环境下的数据隔离与共享挑战。
2290 44
|
缓存 安全 Java
【Java并发】【ConcurrentHashMap】适合初学体质的ConcurrentHashMap入门
ConcurrentHashMap是Java中线程安全的哈希表实现,支持高并发读写操作。相比Hashtable,它通过分段锁(JDK1.7)或CAS+synchronized(JDK1.8)实现更细粒度锁控制,提升性能与安全性。本文详细介绍其构造方法、添加/获取/删除元素等常用操作,并对比JDK1.7和1.8的区别,帮助开发者深入理解与使用ConcurrentHashMap。欢迎关注,了解更多!
1214 5
【Java并发】【ConcurrentHashMap】适合初学体质的ConcurrentHashMap入门
|
存储 缓存 人工智能
【原理】【Java并发】【synchronized】适合中学者体质的synchronized原理
本文深入解析了Java中`synchronized`关键字的底层原理,从代码块与方法修饰的区别到锁升级机制,内容详尽。通过`monitorenter`和`monitorexit`指令,阐述了`synchronized`实现原子性、有序性和可见性的原理。同时,详细分析了锁升级流程:无锁 → 偏向锁 → 轻量级锁 → 重量级锁,结合对象头`MarkWord`的变化,揭示JVM优化锁性能的策略。此外,还探讨了Monitor的内部结构及线程竞争锁的过程,并介绍了锁消除与锁粗化等优化手段。最后,结合实际案例,帮助读者全面理解`synchronized`在并发编程中的作用与细节。
1110 8
【原理】【Java并发】【synchronized】适合中学者体质的synchronized原理
|
消息中间件 中间件 Kafka
分布式事务最全详解 ,看这篇就够了!
本文详解分布式事务的一致性及实战解决方案,包括CAP理论、BASE理论及2PC、TCC、消息队列等常见方案,助你深入理解分布式系统的核心技术。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
分布式事务最全详解 ,看这篇就够了!

热门文章

最新文章