• Java多线程2.2-synchronized 实现原理


    //阅读学习《Java并发编程的艺术》笔记,第二章

    目录

    synchronized 的应用

    1-静态例子:类锁

    2-非静态例子:对象锁

    3-总结:(面试点)

    Synchonized 在JVM 里的实现原理:

    2.2.1 Java 对象头

    2.2.2 锁的升级与对比(面试必面)


    synchronized 的应用

    synchronized修饰方法和代码块。(修饰变量会使变量既不能读也不能写)

    锁住方法:是指不让拷贝该方法进行压栈操作了。只能有一个拷贝执行该方法,这个执行完下一个才能拷贝执行。

    □ 对于普通同步方法,锁是当前实例对象。

    □ 对于静态同步方法,锁是当前类的Class 对象。

    □ 对于同步方法块,锁是Synchonized 括号里配置的对象。

    1-静态例子:类锁

    运行结果:线程1执行结束释放锁,线程2才能调用m3执行

    示意图:因为是静态方法,所以m1在方法区

    2-非静态例子:对象锁

    运行结果:线程1执行结束,线程2才能执行。

    示意图:静态方法在方法区,非静态方法伴随每个对象,都有一份。

    3-总结:(面试点)

    非静态的是对象锁,静态的是类锁;静态的加锁方法互斥;非静态的加锁方法互斥;不同类类型的不互斥

    1、synchronized修饰静态方法-类锁

    调用加锁的静态方法,锁住的是一个类。

    其他的带锁的静态方法都不可以被调用。

    静态方法只有一份,属于类,不管通过类还是对象,调用的都是那一份。

    2、synchronized修饰非静态方法-对象锁

    调用对象a加锁的非静态方法,锁住的是这个方法的对象,即对象a。

    其他的对象a带锁的非静态方法都不可以被调用。

    其他对象b、对象c不受影响。

    3、synchronized修饰代码块

    4、加锁和不加锁的方法调用互不干扰,对象锁和类锁互不干扰

    凡是被synchronized修饰的方法,都必须排队使用


    Synchonized 在JVM 里的实现原理:

    JVM 基于进入和退出Monitor 对象来实现

    代码块同步是使用monitorenter 和monitorexit 指令。

    monitorenter 指令是在编译后插入到同步代码块的开始位置,而monitorexit 是插入到方法结束处和异常处, JVM 要保证每个monitorenter 必须有对应的monitorexit 与之配对。任何对象都有一个monitor 与之关联,当且一个monitor 被持有后,它将处千锁定状态。线程执行到monitorenter 指令时,将会尝试获取对象所对应的monitor 的所有权,即尝试获得对象的锁。

    2.2.1 Java 对象头

    Mark Word,对象头中用了32bit存储对象的hashCode 或锁信息等。

    访问对象的时候去判断对象头锁标志位。

    2.2.2 锁的升级与对比(面试必面)

    偏向、轻量、重量说的是synchronized的三种状态。

    无锁状态、偏向锁状态(可以设置为没有)、轻量级锁状态和重量级锁状态

    这几个状态会随着竞争情况逐渐升级,锁可以升级但不能降级。

    偏向锁:

    场景:没有竞争,没有并发的情况下,比较快。

    加锁过程简单,直接在对象头增加自己线程的ID;线程下次再次调用时,去查看对象头中的线程ID,如果是自己的,直接调用执行。

    轻量级锁(自旋锁):

    场景:最多两三个,小于5个的线程竞争。

    在竞争少时,如果依靠等待通知才能来竞争是比较慢的,所以通过死循环自旋查看,这样速度很快,一释放就能感知到。

    自旋锁能够在别的线程释放锁之后立马知道,然后去竞争。(反应快)

    自旋只适用于少量线程低并发,在高并发情况下对CPU的开销太大了;因为一个线程持有锁,其余的线程都需要一直死循环访问,即占用CPU自旋。

    重量级锁:

    场景:两位数以上竞争。

    所以在高并发情况下,轻量级锁需要升级为重量级锁。

    竞争失败的线程进入阻塞队列,不额外消耗CPU,等待执行完的线程通知唤醒,再进入就绪队列竞争。

    //没有并发偏向锁最快,低并发轻量级锁最快,高并发重量级锁最快。

    //偏向锁用于无竞争情况下,轻量级锁个位数竞争,重量级锁两位数以上竞争。

  • 相关阅读:
    [好题][曼哈顿距离][二分]Taxi 2022杭电多校第3场 1011
    Spring Boot集成SpringFox 3.0与Pageable参数处理
    Factuality Challenges in the Era of Large Language Models
    【Ubuntu】创建C++运行环境
    php获取文件扩展名的三种方法
    docker部署mysql8避坑版,看这一篇就够了
    Linux安装redis详细教程
    LinkedIn领英开发客户方法大全(篇一)
    Rust借用几种变化情况分析
    SpringCloud浅学习
  • 原文地址:https://blog.csdn.net/weixin_44151292/article/details/124273762