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

相关文章
|
9月前
|
SQL 存储 关系型数据库
简单聊聊MySQL的三大日志(Redo Log、Binlog和Undo Log)各有什么区别
在MySQL数据库管理中,理解Redo Log(重做日志)、Binlog(二进制日志)和Undo Log(回滚日志)至关重要。Redo Log确保数据持久性和崩溃恢复;Binlog用于主从复制和数据恢复,记录逻辑操作;Undo Log支持事务的原子性和隔离性,实现回滚与MVCC。三者协同工作,保障事务ACID特性。文章还详细解析了日志写入流程及可能的异常情况,帮助深入理解数据库日志机制。
1072 0
|
3月前
|
关系型数据库 MySQL Java
SpringBoot集成Sharding-Jdbc分库分表
ShardingSphere是一套开源分布式数据库中间件解决方案,包含Sharding-JDBC、Sharding-Proxy和Sharding-Sidecar三款产品,提供数据分片、分布式事务和数据库治理功能,适用于多样化应用场景。
480 0
SpringBoot集成Sharding-Jdbc分库分表
|
8月前
|
存储 安全 Java
ThreadLocal - 原理与应用场景详解
ThreadLocal是Java中用于实现线程隔离的重要工具,为每个线程提供独立的变量副本,避免多线程数据共享带来的安全问题。其核心原理是通过 ThreadLocalMap 实现键值对存储,每个线程维护自己的存储空间。ThreadLocal 广泛应用于线程隔离、跨层数据传递、复杂调用链路的全局参数传递及数据库连接管理等场景。此外,InheritableThreadLocal 支持子线程继承父线程的变量值,而 TransmittableThreadLocal 则解决了线程池中变量传递的问题,提升了多线程上下文管理的可靠性。深入理解这些机制,有助于开发者更好地解决多线程环境下的数据隔离与共享挑战。
1561 43
|
消息中间件 中间件 Kafka
分布式事务最全详解 ,看这篇就够了!
本文详解分布式事务的一致性及实战解决方案,包括CAP理论、BASE理论及2PC、TCC、消息队列等常见方案,助你深入理解分布式系统的核心技术。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
分布式事务最全详解 ,看这篇就够了!
|
9月前
|
Java Spring
JDK动态代理和CGLIB动态代理的区别
Spring AOP中的动态代理主要有两种方式,JDK动态代理和CGLIB动态代理: ● JDK动态代理只提供接口的代理,不支持类的代理Proxy.newProxyInstance(类加载器, 代理对象实现的所有接口, 代理执行器) ● CGLIB是通过继承的方式做的动态代理 , 如果某个类被标记为final,那么它是无法使用 CGLIB做动态代理的。Enhancer.create(父类的字节码对象, 代理执行器)
|
10月前
|
消息中间件 存储 监控
RabbitMQ如何保证消息可靠性?
RabbitMQ通过多种机制确保消息的可靠性,包括消息持久化、确认机制、消息重试与死信队列、消息去重、高可用性配置以及监控与告警机制。这些措施共同构成了RabbitMQ可靠消息传递的基础,帮助开发者在构建分布式系统时有效避免消息丢失和重复处理问题。理解并正确实施这些技术,将显著提高应用系统的稳定性和用户体验。
630 14
|
11月前
|
消息中间件 算法 调度
分布式系统学习10:分布式事务
本文是小卷关于分布式系统架构学习系列的第13篇,重点探讨了分布式事务的相关知识。随着业务增长,单体架构拆分为微服务后,传统的本地事务无法满足需求,因此需要引入分布式事务来保证数据一致性。文中详细介绍了分布式事务的必要性、实现方案及其优缺点,包括刚性事务(如2PC、3PC)和柔性事务(如TCC、Saga、本地消息表、MQ事务、最大努力通知)。同时,还介绍了Seata框架作为开源的分布式事务解决方案,提供了多种事务模式,简化了分布式事务的实现。
473 5
|
SQL 关系型数据库 MySQL
京东面试:什么情况下 mysql RR不能解决幻读? RR隔离mysql如何实现?
老架构师尼恩在其读者交流群中分享了关于MySQL事务隔离级别的深入解析,特别针对RR级隔离如何解决幻读问题进行了详细讨论。文章不仅解释了ACID中的隔离性概念,还列举了四种事务隔离级别(未提交读、提交读、可重复读、串行读)的特点及应用场景。尼恩通过具体的例子和图表,清晰地展示了不同隔离级别下的并发事务问题(脏读、不可重复读、幻读)及其解决方案,特别是RR级隔离下的MVCC机制如何通过快照读和当前读来防止幻读。此外,尼恩还提供了相关面试题的解答技巧和参考资料,帮助读者更好地准备技术面试。更多详细内容和实战案例可在《尼恩Java面试宝典》中找到。
|
存储 缓存 安全
ConcurrentHashMap的实现原理,非常详细,一文吃透!
本文详细解析了ConcurrentHashMap的实现原理,深入探讨了分段锁、CAS操作和红黑树等关键技术,帮助全面理解ConcurrentHashMap的并发机制。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
ConcurrentHashMap的实现原理,非常详细,一文吃透!