JUC并发编程之Synchronized锁优化

简介: HotSpot虚拟机中,对象在内存中存储的布局可以分为三块区域:对象头(Header)、实例数据(Instance Data)和对齐填充(Padding)。

1. Java对象头


HotSpot虚拟机中,对象在内存中存储的布局可以分为三块区域:对象头(Header)、实例数据(Instance Data)和对齐填充(Padding)。



对象头是对象在内存中的元数据信息,它包含了对象的一些重要信息,如对象的锁状态、类元数据指针、数组长度等。对象头是Java虚拟机(JVM)管理和操作对象的关键部分。


Java对象头通常包括以下信息:


Mark Word(标记字):Mark Word是对象头中最重要的部分,占据了对象头的大部分空间。它包含了对象的哈希码、锁信息、垃圾回收信息等。Mark Word的具体结构因JVM实现而异,通常包括以下内容:


对象标志位:用于标识对象的状态,例如是否被锁定、是否已经被回收等。

哈希码:用于支持hashCode方法,以及在哈希表中查找对象的位置。

分代年龄:用于垃圾回收的分代算法,标记对象所属的年代。

锁信息:用于支持同步操作,包括偏向锁、轻量级锁和重量级锁的状态信息。

类型指针:类型指针指向对象的类元数据,它用于确定对象所属的类,以支持对象的方法调用和字段访问。


数组长度(仅对数组对象有效):如果对象是数组,对象头中会包括数组长度信息。


对象头的结构和大小可能会因不同的JVM实现和对象类型而异。对象头通常占用一定的内存空间,因此它会增加每个对象的内存开销。对象头的信息对于垃圾回收、同步和虚拟机运行时的对象操作非常重要。其中Mark Word结构如下图所示。



2. Synchronized锁优化


jdk1.6之前,synchronized属于重量级锁(悲观锁) ,jdk1.6之后被进行了大幅度优化,支持锁升级制度缓解加锁和解锁造成的性能费,锁的级别采用: 偏向锁 -> 轻量级锁 -> 重量级锁。


原子性: synchronized依靠两个字节码指令monitorenter和monitorexit,可以保证被synchronized修饰的代码在同一时间只能被一个线程访问


可见性: JMM(Java内存模型)规定,内存主要分为主内存和工作内存两种,每个线程拥有不同的工作内存,线程工作时会从主内存中拷贝一份变量到工作内存中。代码执行后,有时工作内存中的变量无法及时刷新到主内存中,或者工作内存无法及时获取主内存的最新值,导致共享变量在不同线程间处于不可见性,由此JMM对synchronized做了2条规定:


a.线程解锁前,必须把变量的最新值刷新到主内存中。


b.线程加锁时,先清空工作内存中的变量值,从主内存中重新获取最新值到工作内存中


.有序性: 有时候编译器和处理器为了提升代码效率,会进行指令重排序,但是as-if-serial规定无论怎么重排序,单线程程序的执行结果都不能被改变,而synchronized保证了被修饰的程序在同一时间内只能被同一线程访问, 所以其也算是保证了有序性,但synchronized实际上并不是禁止了被修饰的代码指令重排序。


2.1 偏向锁


偏向锁的思想是,如果一个线程获得了锁,那么锁就进入偏向模式,此时,Mark Word的结构也变为偏向锁结构,当这个线程再次请求锁时,无需再做任何同步操作即可再次获取锁,这样就省去了大量有关锁申请的操作,从而也就提供程序的性能。所以对于没有锁竞争的场合,偏向锁有很好的优化效果,但是在有多线程竞争锁的场合,偏向锁就失效了,这种场合下不应该使用偏向锁,否则会得不偿失,偏向锁失败后,将会优先升级为轻量级锁 基本工作过程:

当线程A访问代码块并获取锁对象时,会通过CAS在Mark Word中记录偏向的锁的threadID,因为偏向锁不会主动释放锁,因此以后再次获取锁的时候,需要比较当前线程的 threadID 和 Mark Word 中的threadID是否一致,如果一致,则无需使用CAS来加锁、解锁;如果不一致,则是因为有其他线程如线程b 来竞争该锁,而偏向锁时不会主动释放锁,因此 Mark Word 存储的还是 线程a 的threadID,那么需要查看 Mark Word 中记录的 线程a 是否存活,如果没有存活,那么锁对象被重置为无锁状态,线程b 可以竞争将其设置为偏向锁;如果存活,那么立刻查找线程a的栈帧信息,如果还是需要继续持有这个锁, 那么暂停当前线程a,撤销偏向锁,升级为轻量级锁,如果 线程不再使用该锁,那么将锁状态设为无锁状态,重新偏向新的线程。


在java中偏向锁是默认开启的,绝大多数 情况下,对于加锁的程序大多都会有两个以上的线程去竞争,如果开启偏向锁,反而会加剧锁的资源消耗,可以通过jvm参数启动或关闭偏向锁:


-XX:-UseBiasedLocking = false
    //偏向锁的启动延迟默认为5秒,可以取消这个延迟:
XX:BiasedLockingStartUpDelay=0


2.2 轻量级锁


当多个线程竞争同一个锁时,偏向锁将转化为轻量级锁。轻量级锁通过CAS(Compare and Swap)操作来尝试获取锁,而不会让线程阻塞。如果CAS操作成功,线程获得锁;否则,线程将升级为重量级锁。轻量级锁是由偏向锁升级而来,它考虑的情况是竞争锁的线程不多,而且线程持有锁的时间也不长的情景。轻量级锁能够提升程序性能的依据是“对绝大部分的锁,在整个同步周期内都不存在竞争”。轻量级锁加锁流程如下图所示。








2.3 重量级锁


当轻量级锁无法满足需求,多个线程仍然竞争同一个锁时,锁会升级为重量级锁。在这种情况下,线程将阻塞,直到获取锁。


2.4 锁消除


锁消除是一种Java虚拟机(JVM)和编译器进行的优化技术,用于自动消除不必要的锁操作,以提高程序的性能。锁消除通常用于优化多线程程序中的同步操作。如果编译器确定某个锁的作用域在程序中是局限的,即锁只在某个特定的线程范围内使用,那么它就有可能被消除。代码示例如下:


public class test {
    public static void main(String[] args) {
        int count=0;
        for(int i=0;i<100;i++){
            Object ob=new Object();
            synchronized (ob){
                count++;
            }
        }
    }
}


2.5 各种锁对比


参考:

链接:https://juejin.cn/post/7292955463955906560

相关文章
|
2月前
|
安全 Java
Java并发编程:Synchronized及其实现原理
Java并发编程:Synchronized及其实现原理
25 4
|
10天前
|
安全 Java 程序员
Java并发编程:理解并应用ReentrantLock
【4月更文挑战第30天】 在多线程的世界中,高效且安全地管理共享资源是至关重要的。本文深入探讨了Java中的一种强大同步工具——ReentrantLock。我们将从其设计原理出发,通过实例演示其在解决并发问题中的实际应用,以及如何比传统的synchronized关键字提供更灵活的锁定机制。文章还将讨论在使用ReentrantLock时可能遇到的一些挑战和最佳实践,帮助开发者避免常见陷阱,提高程序性能和稳定性。
|
1月前
|
安全 Java
【并发编程】Synchronized解决共享变量分析
【并发编程】Synchronized解决共享变量分析
|
8月前
|
Java
并发编程——ReentrantLock
Java中提供锁,一般就是synchronized和lock锁,ReentrantLock跟synchronized一样都是互斥锁。如果竞争比较激烈,推荐lock锁,效率更高。如果几乎没有竞争,推荐synchronized。
17 0
|
8月前
|
存储 缓存 安全
并发编程——synchronized
原子性、有序性、可见性
25 0
|
8月前
|
Java
多线程和并发编程(3)—AQS和ReentrantLock实现的互斥锁
多线程和并发编程(3)—AQS和ReentrantLock实现的互斥锁
51 0
|
9月前
|
缓存 监控 安全
JUC并发编程之线程锁(一)
1.ReentrantLock(互斥锁)、2.ReentRantReaderWriterLock(互斥读写锁)、3.StampedLock(无障碍锁)、4.Condition(自定义锁)、5.LockSupport
57 0
|
10月前
|
存储 SpringCloudAlibaba 安全
JUC并发编程(四):synchronized底层原理和锁升级优化
`synchronized`翻译过来是**同步**的意思,它是Java中一个关键字,是JVM层面提供的同步锁机制,用于保证多线程访问同一资源的可见性、互斥性。即当一个线程已经获取资源锁时,其他试图获取的线程只能等待或者阻塞在那里。
67 0
JUC并发编程(四):synchronized底层原理和锁升级优化
|
12月前
|
安全 调度
【并发编程】synchronized底层原理及对象锁和类锁实践
【并发编程】synchronized底层原理及对象锁和类锁实践
【并发编程】synchronized底层原理及对象锁和类锁实践
|
Java 开发者
并发编程(五)synchronized
并发编程(五)synchronized
123 0