一文搞懂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++;
        }
    }

相关文章
|
8月前
|
存储 安全 Java
synchronized 锁升级
JDK 6 引入的 synchronized 锁升级机制,通过偏向锁、轻量级锁和重量级锁的动态切换,优化了多线程同步性能。该机制根据竞争情况逐步升级锁状态,减少线程阻塞和系统调用开销,从而提升并发效率。
374 0
|
缓存 Java 应用服务中间件
Tomcat是如何打破"双亲委派"机制的?
上文我们详细了解了类加载以及什么是双亲委派机制,相信很多童鞋都了解Tomcat打破了双亲委派机制,本文将对Tomcat为什么要打破双亲委派机制,以及Tomcat是如何打破双亲委派机制的,进行完整性的复盘与解析。
3991 0
Tomcat是如何打破"双亲委派"机制的?
|
5月前
|
缓存 NoSQL 关系型数据库
MySQL 与 Redis 如何保证双写一致性?
我是小假 期待与你的下一次相遇 ~
631 7
|
16天前
|
缓存 监控 算法
吃透 JVM 内存管理与调优:从底层原理到生产级落地实战(JDK17 专属)
本文深入解析JDK17 JVM内存管理与调优。首先剖析JVM内存模型核心架构,包括线程私有区域(程序计数器、虚拟机栈、本地方法栈)和共享区域(堆、元空间等)。通过可复现代码示例演示栈溢出、堆OOM等异常场景,并介绍jstat、jstack等排查工具。详细讲解垃圾回收算法(标记-清除、复制、整理)及JDK17主流收集器(G1、ZGC等)的适用场景。重点阐述生产级调优全流程:从监控定位问题到参数优化,提供常见问题排查方案和参数配置最佳实践。
210 5
|
Java 存储
线程池的核心参数有哪些?
线程池七大核心参数:核心/最大线程数、线程保持时间及单位、阻塞队列、线程工厂与拒绝策略。
1203 79
|
11月前
|
存储 安全 Java
ThreadLocal - 原理与应用场景详解
ThreadLocal是Java中用于实现线程隔离的重要工具,为每个线程提供独立的变量副本,避免多线程数据共享带来的安全问题。其核心原理是通过 ThreadLocalMap 实现键值对存储,每个线程维护自己的存储空间。ThreadLocal 广泛应用于线程隔离、跨层数据传递、复杂调用链路的全局参数传递及数据库连接管理等场景。此外,InheritableThreadLocal 支持子线程继承父线程的变量值,而 TransmittableThreadLocal 则解决了线程池中变量传递的问题,提升了多线程上下文管理的可靠性。深入理解这些机制,有助于开发者更好地解决多线程环境下的数据隔离与共享挑战。
1959 43
|
前端开发 安全 Java
2025春招,Spring 面试题汇总
本文详细整理了2025年春招必备的Spring面试题,分为基础和高级两大部分,帮助求职者全面掌握Spring相关知识点,结合实际项目经验,提升面试成功率。内容涉及Spring框架、AOP、事务管理、数据库集成、Spring Boot、Spring Security、微服务架构等,助力你在春招中脱颖而出。
3121 0
|
9月前
|
缓存 NoSQL 算法
高并发秒杀系统实战(Redis+Lua分布式锁防超卖与库存扣减优化)
秒杀系统面临瞬时高并发、资源竞争和数据一致性挑战。传统方案如数据库锁或应用层锁存在性能瓶颈或分布式问题,而基于Redis的分布式锁与Lua脚本原子操作成为高效解决方案。通过Redis的`SETNX`实现分布式锁,结合Lua脚本完成库存扣减,确保操作原子性并大幅提升性能(QPS从120提升至8,200)。此外,分段库存策略、多级限流及服务降级机制进一步优化系统稳定性。最佳实践包括分层防控、黄金扣减法则与容灾设计,强调根据业务特性灵活组合技术手段以应对高并发场景。
2529 7
|
11月前
|
缓存 安全 Java
【Java并发】【ConcurrentHashMap】适合初学体质的ConcurrentHashMap入门
ConcurrentHashMap是Java中线程安全的哈希表实现,支持高并发读写操作。相比Hashtable,它通过分段锁(JDK1.7)或CAS+synchronized(JDK1.8)实现更细粒度锁控制,提升性能与安全性。本文详细介绍其构造方法、添加/获取/删除元素等常用操作,并对比JDK1.7和1.8的区别,帮助开发者深入理解与使用ConcurrentHashMap。欢迎关注,了解更多!
827 5
【Java并发】【ConcurrentHashMap】适合初学体质的ConcurrentHashMap入门
|
存储 缓存 人工智能
【原理】【Java并发】【synchronized】适合中学者体质的synchronized原理
本文深入解析了Java中`synchronized`关键字的底层原理,从代码块与方法修饰的区别到锁升级机制,内容详尽。通过`monitorenter`和`monitorexit`指令,阐述了`synchronized`实现原子性、有序性和可见性的原理。同时,详细分析了锁升级流程:无锁 → 偏向锁 → 轻量级锁 → 重量级锁,结合对象头`MarkWord`的变化,揭示JVM优化锁性能的策略。此外,还探讨了Monitor的内部结构及线程竞争锁的过程,并介绍了锁消除与锁粗化等优化手段。最后,结合实际案例,帮助读者全面理解`synchronized`在并发编程中的作用与细节。
868 8
【原理】【Java并发】【synchronized】适合中学者体质的synchronized原理

热门文章

最新文章