首页 > 其他分享 >synchronized

synchronized

时间:2024-08-30 13:37:08浏览次数:10  
标签:加锁 操作系统 synchronized 线程 自旋 id

要想理解 synchronized 原理,必须要了解 cas 和 用户态、内核态的理论

synchronized 是关键字,具体怎么实现要翻 cpp、汇编代码,记住理论就行了

CAS

全称叫 Compare And Swap 或者 Compare And Set,比较并交换、比较并设置。具体是:在执行操作之前,先比较当前内存中的值是否等于期望值,如果相等,则执行修改操作;如果不相等,则不执行修改操作,继续进行比较,直到内存中的值与期望值相等为止

举个例子,比如变量 a = 1,要做 a++ 操作

  1. 线程读取 a 的值,保存在自己的栈内(每个线程有自己的栈空间,变量的值保存在 cpu 寄存器)
  2. 现在已经拿到 a 的值了,做 a++,结果是 2
  3. 把 2 回写到 变量 a 中,不是直接回写,先再次读取a的值,判断是否符合条件才决定是否回写
    1. 再次读取 a 的值还是1(说明没有别的线程修改),就把2回写
    2. 如果再次读取的值不是1了,说明别的a已经被别的线程修改了,2就不会回写
  4. 如果重新读取的a不是1,重新做a++,重做的顺序和上面一样,直到成功+1

这个过程是有问题的,比较经典的是 ABA 问题,这个可以通过版本号解决

除了 ABA 还有个更深入的问题,a 一开始是1,a++ 做完,对比 a,然后把新的值写入 a 的过程中,对比和写入是必须保证原子性的,这条命令不能被打断,这是怎么保证的?java 调用 c++,c++ 调用汇编,给这条指令上了个锁(要证明就要去翻 jvm 的 cpp 代码,还要能看懂汇编代码)

用户态、内核态

这是操作系统的两种运行模式,不同模式有不同命令,内核态的命令一般程序不能直接调用执行,需要经过操作系统,操作系统执行这些高级别的命令。JVM 是已用户态的模式在运行,想要加一把重量级锁,这个只能用户态跟操作系统发起申请,操作系统接收到指令然后调用内核态的指令,这个开销是比较大的

比如 java 不能直接操作内存,只能间接通过 UnSafe 类访问,比如前端 js 不能操作系统文件,再比如普通程序不能直接修改操作系统内核结构等等

synchronized

加锁的方式就不说了,同步方法,同步代码块等

synchronized 可以给类加锁,可以给对象加锁,究竟是怎么加的?修改对象头信息,修改成功就表示加锁成功,可以使用 JOL 分析对象内存分布

jvm 启动 4 秒后开启偏向锁,可以在同步代码块中对一个对象加锁(比如 obj),程序启动在主方法中使用 JOL 分析对象内存分布,休眠5秒,然后调用同步代码块的方法,再使用 JOL 打印内存分布,会发现两次答应的对象头不一样

也可以配置延迟时间为0,jvm 一启动就开启偏向锁,锁升级过程如下

  1. 创建对象 obj,这时是无锁,对象头是 obj 的信息,没有和锁相关的信息
  2. 遇到 synchronized 时,加锁,这时加的是偏向锁
    1. 具体是对象头里 markword 的线程id改为当前持有锁的线程 id
    2. 对象头有哪个线程id,就表示这个对象被哪个线程持有锁
    3. 后续如果有重入或竞争先对比线程 id,如果 id 一致,没有竞争,一直是偏向锁
  3. 如果有线程竞争,升级为自旋锁
    1. 也叫轻量级锁、无锁(这个无锁指的是没加重量级锁),CAS 实现,别的线程一直自旋等待
    2. 具体是别的线程一直CAS自旋尝试将对象头的 markword 的线程 id 设置成自己的,如果设置成功就表示持有锁了
  4. 如果竞争加剧,升级为重量级锁
    1. 哪种条件视为竞争加剧?
      1. jdk1.6及以前:自旋次数超过10次,或自选线程数量超过cpu核数一半,自选次数可配置,--XX:PreBlockSpin
      2. jdk1.6 之后:由 JVM 自己判断自旋次数、自旋线程数是多少时视为竞争加剧
    2. 和内核态通信,向操作系统申请资源

为什么有轻量级锁还要重量级锁?线程自旋是要消耗 CPU 的,当线程数量过多显然不适合继续自旋。重量级锁会把这些等待的线程放进一个队列,这个队列里面的线程不会消耗 CPU

标签:加锁,操作系统,synchronized,线程,自旋,id
From: https://www.cnblogs.com/cyrushuang/p/18388594

相关文章

  • Android开发 - synchronized 关键字控制多个线程对共享资源的访问解析
    什么是synchronizedsynchronized一个关键字,用于实现线程同步。其主要作用是控制多个线程对共享资源的访问,确保被synchronized修饰的代码块或方法同一时间只有一个线程可以执行,从而避免数据不一致的问题为什么需要synchronized在多线程编程中,多个线程可能同时访问和修改......
  • Synchronized重量级锁原理和实战(五)
    在JVM中,每个对象都关联这一个监视器,这里的对象包含可Object实例和Class实例.监视器是一个同步工具,相当于一个凭证,拿到这个凭证就可以进入临界区执行操作,没有拿到凭证就只能阻塞等待.重量级锁通过监视器的方式保证了任何时间内只允许一个线程通过监视器保护的临界区代码.......
  • Java并发编程 - 基础(悲观锁与synchronized)(偏向锁、轻量级锁、锁优化)
    Java并发编程中的悲观锁和synchronized关键字,以及Java内存模型中的锁优化机制(如偏向锁、轻量级锁)都是非常重要的概念。下面将详细介绍这些内容。悲观锁(PessimisticLocking)悲观锁假设数据会发生冲突,因此在读取数据时就加锁,以防止其他线程修改数据。这种方式虽然能保......
  • 操作集合的工具类:Collections(以及将线程变安全的synchronized方法)
      静态成员方法:    publicstatic<T>voidsort(List<T>list)升序    publicstatic<T>intbinarySearch(List<?>list,Tkey)二分查找    publicstatic<T>Tmax(Collection<?>coll)找最大值    publicstaticvoidreve......
  • synchronized轻量级锁原理和实战(四)
    引入轻量级锁的目的多线程竞争不激烈的情况下,通过CAS机制竞争减少重量级锁产生的性能消耗.重量级锁使用了操作系统底层的互斥锁,会导致线程在用户态和核心态之间切换.带来性能上的损耗.轻量级锁的核心原理轻量级锁存在的目的本身就是为了减少线程从内核态和用户态的切换,从......
  • 面试题:在Java中,volatile 关键字的作用是什么?它与 synchronized 关键字在实现线程同步
    面试题:在Java中,volatile 关键字的作用是什么?它与 synchronized 关键字在实现线程同步方面有何不同?请深入探讨其背后的原理和应用场景。更多答案在这里,手机或电脑浏览器就可以打开, 面霸宝典【全 拼音】.com 这里可以优化简历,模拟面试,企业项目源码,最新最全大厂高并......
  • [Java并发]Synchronized底层原理
    synchronized底层语义原理Java虚拟机中的同步(Synchronization)基于进入和退出管程(Monitor)对象实现。在Java语言中,同步用的最多的地方可能是被synchronized修饰的同步方法。同步方法并不是由monitorenter和monitorexit指令来实现同步的,而是由方法调用指令读取运行时......
  • synchronized升级过程
    1.对象有三个区域对象头/实例数据/对其填充对象头又包含MarkWord/类型指针->指向方法区/数组长度MarkWord如下图所示2.偏向锁当线程首次进入synchronized,他会将对象头的markwork更新为偏向锁。JDK已废除3.轻量锁当线程获取已被偏向的锁时,会将锁升级为轻量锁。具体过......
  • synchronized 关键字
    1synchronized关键字的作用互斥访问:当一个线程获得了由synchronized修饰的方法或代码块的锁后,其他线程必须等待该锁被释放才能继续执行。这种机制保证了同一时间只有一个线程可以执行被synchronized修饰的代码段。可见性:synchronized关键字确保了当一个线程修改了......
  • synchronized
    synchronized关键字来保证线程安全的,被sychronized锁住的代码部分,同一时刻只能有一个线程可以访问,其他线程会block(同一个对象内,不同对象间不会影响)。由于synchronized的机制是在同一时刻只能有一个线程操作,其他的线程阻塞或者轮询等待,在线程竞争激烈的情况下,这种方式的效率会非常......