tip: 作为程序员一定学习编程之道,一定要对代码的编写有追求,不能实现就完事了。我们应该让自己写的代码更加优雅,即使这会费时费力。

推荐:体系化学习Java(Java面试专题)

文章目录

  • 一、synchronized 的底层原理
  • 二、synchronized 的锁升级原理
    • 1、偏向锁
    • 2、轻量级锁
    • 3、重量级锁

一、synchronized 的底层原理

synchronized 的底层是通过 Java 中的**监视器锁(monitor)**来实现的。每个 Java 对象都有一个与之对应的监视器锁,当一个线程获取了该对象的监视器锁,就可以执行 synchronized 代码块或方法。其他线程只能等待该线程释放锁,才能获取该对象的监视器锁并执行 synchronized 代码块或方法。

在 Java 中,每个对象都有一个与之关联的管程(monitor)。管程包括两个部分:一个是对象头(Object Header),用于存储对象的元数据信息;另一个是监视器锁(Monitor Lock),用于实现线程同步。当一个线程获取了对象的监视器锁,就可以执行 synchronized 代码块或方法,其他线程只能等待该线程释放锁,才能获取该对象的监视器锁并执行 synchronized 代码块或方法。

当一个线程进入 synchronized 代码块或方法时,它会尝试获取对象的监视器锁。如果该锁没有被其他线程占用,则该线程获取锁并继续执行 synchronized 代码块或方法;如果该锁已经被其他线程占用,则该线程会进入锁池(Lock Pool)等待,直到该锁被其他线程释放。

当一个线程释放对象的监视器锁时,它会唤醒锁池中的一个等待线程,让其获取锁并继续执行 synchronized 代码块或方法。如果锁池中有多个等待线程,那么唤醒哪个线程是不确定的,取决于 JVM 的实现。

二、synchronized 的锁升级原理

synchronized 的锁升级指的是在不同的情况下,synchronized 锁的状态会从偏向锁、轻量级锁、重量级锁等级别逐步升级的过程。在 Java 6 及之前的版本中,synchronized 的锁升级过程是固定的,而在 Java 6 及之后的版本中,锁升级过程是根据当前锁的状态和竞争情况动态调整的。

偏向锁:当一个线程访问同步块并获取锁时,会在对象头中记录锁偏向的线程 ID,以后该线程再次进入同步块时,只需判断当前线程 ID 是否与对象头中记录的线程 ID 相同,如果相同,就可以直接进入同步块,无需进行额外的同步操作。如果有其他线程竞争锁,则偏向锁会被撤销。

轻量级锁:当一个线程获取锁失败时,会尝试使用轻量级锁来提高性能。轻量级锁是通过将对象头中的信息复制到线程的栈帧中,然后在栈帧中进行同步操作来实现的。如果在同步过程中发生竞争,则轻量级锁会升级为重量级锁。

重量级锁:当多个线程竞争同一个锁时,会升级为重量级锁。重量级锁是通过操作系统的互斥量来实现的,每次加锁和释放锁都需要进行系统调用,开销较大。

在 Java 6 及之前的版本中,锁升级过程是固定的,即从偏向锁升级到轻量级锁,再升级到重量级锁。而在 Java 6 及之后的版本中,锁升级过程是根据当前锁的状态和竞争情况动态调整的,可以根据实际情况选择偏向锁、轻量级锁或重量级锁,从而提高程序的性能。

1、偏向锁

偏向锁是 Java 中的一种锁优化机制。它的主要目的是减少无竞争情况下的同步操作,从而提高程序的性能。在偏向锁的情况下,当一个线程访问同步块并获取锁时,会在对象头中记录锁偏向的线程 ID,以后该线程再次进入同步块时,只需判断当前线程 ID 是否与对象头中记录的线程 ID 相同,如果相同,就可以直接进入同步块,无需进行额外的同步操作。

偏向锁的优点是可以减少同步操作的开销,尤其是在无竞争的情况下。在无竞争的情况下,偏向锁可以避免多余的同步操作,从而提高程序的性能。另外,偏向锁的实现比较简单,开销也比较小。

偏向锁的缺点是当有其他线程竞争锁时,偏向锁会被撤销,这样就会导致额外的同步操作,从而降低程序的性能。此外,偏向锁只适用于无竞争的情况,如果存在竞争,就需要使用其他的锁机制来保证线程安全。

需要注意的是,偏向锁只适用于单线程访问同步块的情况。如果多个线程访问同一个同步块,就会出现竞争,此时偏向锁会被撤销,从而降低程序的性能。

package com.pany.camp.lock;import org.openjdk.jol.info.ClassLayout;public class BiasedLockDemo {public static void main(String[] args) throws InterruptedException {BiasedLockDemo biasedLockDemo = new BiasedLockDemo();biasedLockDemo.doSomething();System.out.println(ClassLayout.parseInstance(biasedLockDemo).toPrintable());}public synchronized void doSomething() {System.out.println("doSomething() is called");}
}


在上面的输出中,我们可以看到对象头中的第一个字节是 01 ,这个字节的二进制表示是 00000001 ,其中第0位是1,表示这个对象的锁是偏向锁。如果第0位是0,表示这个对象的锁不是偏向锁。

可以通过 -xx:UseBiasedLocking 禁用偏向锁。

2、轻量级锁

轻量级锁是Java虚拟机为了提高多线程程序性能而引入的一种锁优化机制。与传统的重量级锁相比,轻量级锁的锁操作使用了更加轻量级的机制,避免了不必要的线程阻塞和上下文切换,从而提高了多线程程序的执行效率。

轻量级锁的实现原理是,当一个线程第一次进入同步代码块时,Java虚拟机会为该对象分配一个锁记录(Lock Record)并将对象头中的Mark Word复制到锁记录中。然后,虚拟机会尝试使用CAS操作将对象头中的Mark Word替换为指向锁记录的指针,从而将对象的锁状态升级为轻量级锁。如果CAS操作成功,该线程就可以继续执行同步代码块,否则就会退化为重量级锁,从而保证线程安全。

当一个线程持有轻量级锁时,其他线程可以使用CAS操作来尝试获取锁。如果获取成功,就可以继续执行同步代码块。如果获取失败,就会进入自旋状态,等待持有锁的线程释放锁。如果自旋次数超过一定阈值,或者持有锁的线程被阻塞,就会退化为重量级锁。

总之,轻量级锁是Java虚拟机为了提高多线程程序性能而引入的一种锁优化机制,它避免了不必要的线程阻塞和上下文切换,从而提高了多线程程序的执行效率。

package com.pany.camp.lock;import cn.hutool.core.thread.ThreadUtil;
import org.openjdk.jol.info.ClassLayout;public class LightLock {private int count = 0;public synchronized void increment() {count++;}public static void main(String[] args) {final LightLock obj = new LightLock();final int numThreads = 5;final int numIterations = 10000;Thread t1 = new Thread(() -> {ThreadUtil.sleep(1000);System.out.println(ClassLayout.parseInstance(obj).toPrintable());}, "t1");t1.start();// 创建多个线程并启动Thread[] threads = new Thread[numThreads];for (int i = 0; i < numThreads; i++) {threads[i] = new Thread(() -> {for (int j = 0; j < numIterations; j++) {// 对共享对象加锁synchronized (obj) {obj.increment();ThreadUtil.sleep(1);}}});threads[i].start();}System.out.println("Count: " + obj.count);}
}


上面的例子,对象头的 Mark Word 已经替换为指向锁记录的指针,已经升级成轻量级锁了。

3、重量级锁

重量级锁是Java中的一种锁机制,也称为互斥锁。它是基于操作系统的互斥量实现的,需要进行用户态与内核态之间的切换,因此开销比较大,效率较低。当多个线程竞争同一个锁时,如果该锁是重量级锁,那么线程会进入阻塞状态,等待锁的释放。在Java中,synchronized关键字使用的锁就是重量级锁。

重量级锁的实现原理是,在Java虚拟机中,每个对象都与一个监视器关联,当一个线程需要获取该对象的锁时,它会尝试获取该对象的监视器锁。如果该锁已经被其他线程持有,那么该线程就会进入阻塞状态,等待锁的释放。当该锁被释放时,等待队列中的线程会被唤醒,并重新尝试获取锁。

重量级锁的优点是实现简单,可靠性高,不会出现死锁等问题。缺点是由于需要进行用户态与内核态之间的切换,因此开销比较大,效率较低。在多线程环境下,如果使用重量级锁过多,会导致系统性能下降,因此应该根据具体情况选择合适的锁机制。

synchronized 的底层原理相关推荐

  1. 面试必备:synchronized的底层原理?

    最近更新的XX必备系列适合直接背答案,不深究,不喜勿喷. 你能说简单说一下synchronize吗? 可别真简单一句话就说完了呀~ 参考回答: synchronize是java中的关键字,可以用来修饰 ...

  2. 天天用Synchronized,底层原理是个啥?

    作者:liuxiaopeng https://www.cnblogs.com/paddix/p/5367116.html Synchronized 的基本使用 Synchronized 的作用主要有三 ...

  3. synchronized的底层原理

    synchronized使用方式 我们知道并发编程会产生各种问题的源头是可见性,原子性,有序性. 而synchronized能同时保证可见性,原子性,有序性.所以我们在解决并发问题的时候经常用sync ...

  4. 搞定高并发,岂能不懂Synchronized底层原理?

    Synchronized 是 Java 中解决并发问题的一种最常用的方法,也是最简单的一种方法.本文作者将全面剖析 Synchronized 的底层原理. Synchronized 的基本使用 Syn ...

  5. synchronized原理_synchronized 关键字底层原理

    synchronized 关键字底层原理属于 JVM 层面. ① synchronized 修饰同步语句块 public class SynchronizedDemo {public void met ...

  6. synchronized原理_面试必备—Synchronized 关键字使用、底层原理

    在并发编程中存在线程安全问题,主要原因有: 1.存在共享数据 2.多线程共同操作共享数据 关键字synchronized可以保证在同一时刻,只有一个线程可以执行某个方法或某个代码块,同时synchro ...

  7. synchronized关键字的底层原理以及JDK1.6之后的底层优化

    synchronized关键字底层原理属于JVM层面. 1. synchronized关键字修饰同步代码块,synchronized同步代码块的实现使用的是monitorenter和monitorex ...

  8. JUC多线程:synchronized锁机制原理 与 Lock锁机制

    前言: 线程安全是并发编程中的重要关注点,造成线程安全问题的主要原因有两点,一是存在共享数据(也称临界资源),二是存在多条线程共同操作共享数据.因此为了解决这个问题,我们可能需要这样一个方案,当存在多 ...

  9. Android开发中synchronized的实现原理

    synchronized的三种使用方式 **1.修饰实例方法,**作用于当前实例加锁,进入同步代码前要获得当前实例的锁. 没有问题的写法: public class AccountingSync im ...

最新文章

  1. JavaScript 函数的定义
  2. webpack项目上传云服务器,webpack项目上传云服务器
  3. XP下如何恢复Administrator
  4. Transformer升级之路:Sinusoidal位置编码追根溯源
  5. C和指针之字符串实现my_strrchr(char *str, int ch)的函数
  6. 软件设计师1991下午试题1(流程图解析)
  7. 在linux中 如何创建磁盘配额,如何在Linux系统中配置磁盘配额?
  8. mk-parallel-dump 实验
  9. 零基础入门深度学习(2) - 线性单元和梯度下降
  10. LayaAir UI 组件 # Image 位图、Label 标签
  11. 算法48---原子的数量【栈】
  12. html音乐播放器代码大全,关于HTML 音乐播放器代码|音乐播放器网页代码大全(转)...
  13. Revo Uninstaller Pro v3.1.2 测试和评测:
  14. 使用Pytorch搭建U-Net网络并基于DRIVE数据集训练(语义分割)学习笔记
  15. 为什么要学习HashMap的底层原理?
  16. QT VS2019 OpenCV yolo4 摄像头识别人脸
  17. @Deprecated(注解)
  18. 响应式织梦模板家具家居类网站
  19. 上海市证券、保险公司一览
  20. 网易考拉卖身阿里的前夜:HR欲哭无泪,太难了。

热门文章

  1. 【ANFIS分类】基于遗传算法优化模糊和ANFIS实现数据分类附matlab代码
  2. iis/apache + php5 + mysql5_Windows下IIS6/Apache2.2.4+MySQL5.2+PHP5.2.6安装配置方法
  3. 8266+DS3231时钟之语音MP3-TF-16P模块使用【五】
  4. antdpro使用AbortController取消请求
  5. 上传8m以上文件,报错误 101 (net::ERR_CONNECTION_RESET):连接已重置
  6. PHPCMS problems set
  7. 小程序报错 H.createEvent is not a function !已解决
  8. AMD 双核CPU补丁下载及安装方法 (转)
  9. html期末作业代码网页设计——美食主题(6页) HTML+CSS+JavaScript 学生dreamweaver网页设计作业成品
  10. Fiddler无法抓取Chrome包的解决办法