写点什么

Java 中 synchronized 锁的深入理解

  • 2023-05-29
    湖南
  • 本文字数:1481 字

    阅读完需:约 5 分钟

使用范围

  • 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 存储的内容示意图


作者:舒一笑

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

来源:稀土掘金

用户头像

还未添加个人签名 2021-07-28 加入

公众号:该用户快成仙了

评论

发布
暂无评论
Java中synchronized锁的深入理解_Java_做梦都在改BUG_InfoQ写作社区