Java中synchronized锁的深入理解

简介: Java中synchronized锁的深入理解

使用范围

  • synchronized使用上用于同步方法或者同步代码块
  • 在锁实现上是基于对象去实现
  • 使用中用于对static修饰的便是class类锁
  • 使用中用于对非static修饰的便是当前对象锁

synchronized的优化

  • 在jdk1.6中对synchronized做了相关的优化

锁消除

  • 在synchronized修饰的代码块中,要是不涉及操作临界资源的情况,即便你写了synchronized修饰,也不会出发锁机制

锁膨胀

  • 在一个循环中频繁的出现锁资源的获取与释放操作,会带来资源的消耗,于是便会将锁的范围扩大到循环的外边,避免频繁的竞争和获取锁资源而导致的资源消耗
  public void method(){
        for (int i = 0; i < Integer.MAX_VALUE; i++) {
            synchronized ("") {
                // 业务代码
            }
        }
    }

锁升级

  • ReentrantLock中是基于乐观锁的CAS获取线程资源。资源拿不到的情况下才会挂起线程。synchronized在jdk1.6之间完全获取不到锁的情况下立即挂起线程,但是在1.6之后进行了锁的升级与优化。
  • 无锁、匿名偏向:当前对象没有作为锁的存在
  • 偏向锁:当前锁资源,只有一个线程频繁的获取和释放锁,那么只有该线程获取锁是判断是否是同一个线程,如果是线程资源拿走。如果线程不是当前自己的线程,则采用基于CAS的方式,尝试将偏向锁指向当前线程。如果获取不到则触发锁升级为轻量级锁,也就意味着发生了锁竞争的情况。
  • 轻量级锁:使用自旋锁的方式频繁的采用CAS的方式获取锁资源。这里采用的自适应自旋锁(JVM更具上次的自旋结果来进行判断本次的自旋时间长短)。如果成功获取锁资源,资源取走。如果获取锁资源失败,锁升级。
  • 重量级锁:最为传统的synchronized实现方式。拿不到锁资源之间挂起线程,然后进行用户态和内核态的不断切换。。。

synchronized锁的实现原理

  • synchronized锁是基于对象来进行实现的
  • 关于MarkWord的内容展开示意图

    从图中可以看出通过锁的标志位来进行区分锁的不同状态

synchronized锁升级的过程演示

  • 使用之前需要导入一个依赖
    <dependency>
            <groupId>org.openjdk.jol</groupId>
            <artifactId>jol-core</artifactId>
            <version>0.9</version>
        </dependency>

  • 锁在默认情况下,开启了偏向锁的延迟
  • 原因是因为在偏向锁升级为轻量级锁的时候会涉及到偏向锁的撤销,需要等到一个安全点(STW),才能完成对偏向锁的撤销,所以在并发的情况下就可以选择不开启偏向锁,或者设置偏向锁延迟开启
  • 在JVM启动时会大量加载.class文件到内存,该操作会涉及synchronized使用,为了避免出现偏向锁撤销的操作。在启动初期,有一个延迟5s开启偏向锁的操作。
  • 要是正常开启偏向锁,那么就不会出现无锁的状态,而是直接进入匿名偏向锁

  • 变成了偏向锁

/**
 * @author 舒一笑
 * @date 2023/5/28
 */
public class Test15 {
    public static void main(String[] args) throws InterruptedException {
        Thread.sleep(5000);
        Object o = new Object();
        System.out.println(ClassLayout.parseInstance(o).toPrintable());
    //thread 线程偏向锁
        Thread thread = new Thread(()->{
            synchronized (o){
                System.out.println("thread线程 :"+ClassLayout.parseInstance(o).toPrintable());
            }
        });
        thread.start();
        // 轻量级锁 -> 重量级锁
        synchronized (o){
            System.out.println("main线程 :"+ClassLayout.parseInstance(o).toPrintable());
        }

    }

}

锁转换状态示意图

LockRecord和ObjectMonitor存储的内容示意图

如果您觉得我所提供的信息对您有帮助,欢迎您点赞、收藏和评论。如果您想要更深入的交流,您可以添加我的微信号,或者关注我的微信公众号。您的支持和鼓励是我持续写作的动力,我期待与您互动并提供更多有价值的信息。

目录
相关文章
|
4月前
|
安全 Java 调度
Java编程时多线程操作单核服务器可以不加锁吗?
Java编程时多线程操作单核服务器可以不加锁吗?
51 2
|
16天前
|
安全 Java Kotlin
Java多线程——synchronized、volatile 保障可见性
Java多线程中,`synchronized` 和 `volatile` 关键字用于保障可见性。`synchronized` 保证原子性、可见性和有序性,通过锁机制确保线程安全;`volatile` 仅保证可见性和有序性,不保证原子性。代码示例展示了如何使用 `synchronized` 和 `volatile` 解决主线程无法感知子线程修改共享变量的问题。总结:`volatile` 确保不同线程对共享变量操作的可见性,使一个线程修改后,其他线程能立即看到最新值。
|
16天前
|
安全 Java 编译器
深入理解Java中synchronized三种使用方式:助您写出线程安全的代码
`synchronized` 是 Java 中的关键字,用于实现线程同步,确保多个线程互斥访问共享资源。它通过内置的监视器锁机制,防止多个线程同时执行被 `synchronized` 修饰的方法或代码块。`synchronized` 可以修饰非静态方法、静态方法和代码块,分别锁定实例对象、类对象或指定的对象。其底层原理基于 JVM 的指令和对象的监视器,JDK 1.6 后引入了偏向锁、轻量级锁等优化措施,提高了性能。
42 3
|
2月前
|
缓存 Java
java中的公平锁、非公平锁、可重入锁、递归锁、自旋锁、独占锁和共享锁
本文介绍了几种常见的锁机制,包括公平锁与非公平锁、可重入锁与不可重入锁、自旋锁以及读写锁和互斥锁。公平锁按申请顺序分配锁,而非公平锁允许插队。可重入锁允许线程多次获取同一锁,避免死锁。自旋锁通过循环尝试获取锁,减少上下文切换开销。读写锁区分读锁和写锁,提高并发性能。文章还提供了相关代码示例,帮助理解这些锁的实现和使用场景。
java中的公平锁、非公平锁、可重入锁、递归锁、自旋锁、独占锁和共享锁
|
2月前
|
Java 开发者
Java 中的锁是什么意思,有哪些分类?
在Java多线程编程中,锁用于控制多个线程对共享资源的访问,确保数据一致性和正确性。本文探讨锁的概念、作用及分类,包括乐观锁与悲观锁、自旋锁与适应性自旋锁、公平锁与非公平锁、可重入锁和读写锁,同时提供使用锁时的注意事项,帮助开发者提高程序性能和稳定性。
105 3
|
2月前
|
Java 开发者
在Java多线程编程的世界里,Lock接口正逐渐成为高手们的首选,取代了传统的synchronized关键字
在Java多线程编程的世界里,Lock接口正逐渐成为高手们的首选,取代了传统的synchronized关键字
51 4
|
3月前
|
Java
Java 中锁的主要类型
【10月更文挑战第10天】
|
3月前
|
算法 Java 程序员
Java中的Synchronized,你了解多少?
Java中的Synchronized,你了解多少?
|
3月前
|
Java
让星星⭐月亮告诉你,Java synchronized(*.class) synchronized 方法 synchronized(this)分析
本文通过Java代码示例,介绍了`synchronized`关键字在类和实例方法上的使用。总结了三种情况:1) 类级别的锁,多个实例对象在同一时刻只能有一个获取锁;2) 实例方法级别的锁,多个实例对象可以同时执行;3) 同一实例对象的多个线程,同一时刻只能有一个线程执行同步方法。
25 1
|
3月前
|
Java 开发者
在 Java 多线程编程中,Lock 接口正逐渐取代传统的 `synchronized` 关键字,成为高手们的首选
【10月更文挑战第6天】在 Java 多线程编程中,Lock 接口正逐渐取代传统的 `synchronized` 关键字,成为高手们的首选。相比 `synchronized`,Lock 提供了更灵活强大的线程同步机制,包括可中断等待、超时等待、重入锁及读写锁等高级特性,极大提升了多线程应用的性能和可靠性。通过示例对比,可以看出 Lock 接口通过 `lock()` 和 `unlock()` 明确管理锁的获取和释放,避免死锁风险,并支持公平锁选择和条件变量,使其在高并发场景下更具优势。掌握 Lock 接口将助力开发者构建更高效、可靠的多线程应用。
35 2
下一篇
开通oss服务