juc-4-synchronized原理

news2024/11/25 6:37:20

目录

1、synchronized 作用于静态方法

 总结

​编辑

  案例 静态成员变量 (synchronized锁非静态方法)

  案例 静态成员变量 (synchronized锁静态方法 或 直接锁类)

2、监视器锁(monitor)

2.1 synchronized怎么实现的线程安全呢?

3、JDK6 synchronized 的优化

   3.1 CAS讲解

3.2 synchronized

3.2.1 java对象的布局

 3.2.2 偏向锁

 3.2.3 偏向锁的撤销 

3.2.4轻量级锁(自旋锁/自适应自旋锁)


1、synchronized 作用于静态方法

 总结

  1.  当synchronized作用于静态方法时,其锁就是当前类的class对象锁。由于静态成员不专属于任何一个实例对象,是类成员,因此通过class对象锁可以控制静态 成员的并发操作。
  2.  synchronized作用于非静态方法时,也可以直接锁类。也可以控制静态 成员的并发操作。
  3.  synchronized作用于非静态方法时,必须是同一个对象才能控制静态 成员的并发操作。

需要注意的是如果一个线程A调用一个实例对象的非static synchronized方法,而线程B需要调用这个实例对象所属类的静态 synchronized方法,是允许的,不会发生互斥现象,因为访问静态 synchronized 方法占用的锁是当前类的class对象,而访问非静态 synchronized 方法占用的锁是当前实例对象锁

  案例 静态成员变量 (synchronized锁非静态方法)

   synchronized修饰非静态方法时,锁的是当前实例,不同实例就不是同一把锁了,就不是线程安全 

public class ThreadRunnable5 implements Runnable {
    private static int a = 100;
    @SneakyThrows @Override
    public void run() {
            while (true) {
                if (a > 1) {
                    increase4Obj();
                    Thread.sleep(100);
                }
            }
    }
    public synchronized   void increase4Obj(){
            System.out.println(Thread.currentThread().getName() + "==" + a);
            a--;
    }
    public static void main(String[] args) {
        ThreadRunnable5 thread = new ThreadRunnable5();
        new Thread(thread).start();
        new Thread(thread).start();
    }
}

 

  普通方法锁的就是 对象的实例,不同的实例对象时,就是两个锁。无法保证线程安全

  案例 静态成员变量 (synchronized锁静态方法 或 直接锁类)

2、监视器锁(monitor)

一篇就够,synchronized原理详解_小派师兄的博客-CSDN博客_synchronized原理

2.1 synchronized怎么实现的线程安全呢?

2.1 我们反编译下面的代码,看看jvm底层是如何帮助我们实现的线程安全的。

代码

public class ThreadRunnable6  {
    private static Object obj=new Object();

    public synchronized void test(){
        System.out.println("test打印");
    }
    public static void main(String[] args) {
        synchronized (obj){
            System.out.println("同步代码块");
        }
    }
}

执行反编译命令

到目标类的文件夹下
cd target/classes/com/example/juc/create/
对目标类执行命令
javap -p -v -c ThreadRunnable6.class

 找到main方法那段就行

jvm虚拟机规范文档找到指令作用

Chapter 6. The Java Virtual Machine Instruction Set

monitorenter内部结构

可以参考这个博客的一些理解,画的很容易理解,但是也不是很全面

Java并发编程之Monitor工作原理(有图解)_Juice正在路上..的博客-CSDN博客_java monitor原理

java对象头的总体结构,MarkWord的结构、MarkWord和锁的关系_时间都用来泡馍了的博客-CSDN博客_java对象头结构

获取锁资源的流程:

monitor是重量级锁

jvm底层调用会用到内核函数。需要我们由用户态切换到内核态。

那什么是内核态呢?为什么不能直接使用呢?

 我们的应用程序在内存运行的空间叫 用户空间(用户态)。

 它不能直接调用系统的硬件资源,会去损坏我们的硬件(随意删除内存数据,造成死机等)。为了安全,

只有内核能够调用硬件,应用程序靠系统调用,cpu由用户态转为内核态,调用完成后,操作系统会重置cpu为用户态并返回系统调用的结果。  

用户态与内核态来回切换会有大量的系统资源消耗,所以jdk1.6优化了synchronize 。

例如:IO操作,就需要内核态

3、JDK6 synchronized 的优化

   3.1 CAS讲解

跟乐观锁类似,本地内存和主存比较一样即可修改,内存地址和旧的预期值一样 就可以更改 成员变量 。do while用的很好

   

3.2 synchronized

jdk1.6做的优化,无锁---偏向锁---轻量级锁----重量级锁

3.2.1 java对象的布局

对象头:hash码,锁信息(判断是哪种锁状态,重量级锁的指针 moniter位置),gc标志

实例数据:类中属性数据信息,包括父类的属性信息;

对齐数据:jvm分64位和32位, 64位就是8字节,一个对象要被8整除。不够的补齐。

 3.2.2 偏向锁

总结:锁对象结构,一个线程使用的时候,就会是偏向锁,但是有四秒延时,四秒前打印不是偏向锁,四秒后就是偏向锁。

有偏向锁的原因:经过HotSpot作者发现,大多数情况下,锁不仅不存在多线程竞争,而且总是由一个线程多次获取,为了让线程获取锁的代价更低,引入了偏向锁。

偏向锁:会偏向于第一个获取锁的线程,会在对象头存储偏向的线程id。以后该线程进入和退出同步快时只需要检查是否为偏向锁,锁标志位以及ThreadID即可。

偏向锁的基本流程图

步骤二是用CAS保证记录线程id的正确性。

 验证打印对象头信息

        <!--查看对象内存布局-->
        <dependency>
            <groupId>org.openjdk.jol</groupId>
            <artifactId>jol-core</artifactId>
            <version>0.9</version>
        </dependency>
    private static Object obj=new Object();
    public static void main(String[] args) {
        synchronized (obj){
            System.out.println(ClassLayout.parseInstance(obj).toPrintable());
        }
    }

 为什么打印的不是101(偏向锁)?

偏向锁在java1.6是默认启动的,但是要在程序启动后4秒才能激活。可以使用参数关闭延时。如果程序所有锁基本都要处于竞争状态也可以关闭偏向锁。

//关闭延迟开启偏向锁
-XX:BiasedLockingStartupDelay=0
//禁止偏向锁
-XX:-UseBiasedLocking

 3.2.3 偏向锁的撤销 

场景:两个线程竞争的时候就会去撤销偏向锁。

1偏向锁的撤销动作必须等待全局安全点(所有的线程都停下来了)

2暂停拥有偏向锁的线程,判断锁对象是否处于被锁定的状态。

3撤销偏向锁,恢复到无锁(标志位为01)或轻量级锁(标志位为00)的状态

3.2.4轻量级锁(自旋锁/自适应自旋锁)

场景:适用于多个线程交替去获取锁,而不是大量并发去获取锁。

jdk1.4引入自旋锁,1.6引入自适应自旋锁。 如果线程过多很多线程空耗cpu资源。升级为重量级锁(monitor

还有很多细节,实在学的难受,暂时放放。

偏向锁、轻量级锁、自旋锁、重量级锁,看这一篇就够了!_51CTO博客_自旋锁和互斥锁

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/114527.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

互联网技术不再是统领,当下正在发生着一场深刻的变革

拥抱实体经济&#xff0c;绝对是当下互联网玩家们的首要选择。无论是头部的互联网企业来讲&#xff0c;还是新生的互联网玩家而言&#xff0c;它们都不约而同地将关注的焦点聚焦在了这样一个方向上。   透过这一点&#xff0c;我们可以非常明显地感受到&#xff0c;一个全新的…

圣诞节,记录前行中跨过的2022

2022年&#xff0c;我人生的第二十四年&#xff0c;是我大学生活的最后一年&#xff0c;是我职场生涯的第一年&#xff0c;这一年从学生到打工人&#xff0c;从实习生到职场员工&#xff0c;变化了许多&#xff0c;做了许多&#xff0c;收获了许多&#xff0c;同时也成长了许多…

m自适应FSK解调系统误码率matlab仿真

目录 1.算法描述 2.仿真效果预览 3.MATLAB核心程序 4.完整MATLAB 1.算法描述 FSK信号的解调也有非相干和相干两种&#xff0c;FSK信号可以看作是用两个频率源交替传输得到的&#xff0c;所以FSK的接收机由两个并联的ASK接收机组成。 (1)相干解调 相干解调是利用乘法器&…

Minecraft(我的世界) Fabric 1.19.3 服务器搭建教程

Debian系统使用MCSManager9面板搭建MC Java版MOD服务器的教程&#xff0c;本教程用的Fabric1.19.3服务端&#xff0c;用其他服务端的也可以参考一下。 视频教程&#xff1a;https://www.bilibili.com/video/BV1Zd4y1h7zG/ 我的世界(MC) Fabric 1.19.3 开服教程&#xff0c;新手…

IDEA Git 选项栏各项功能详解

IDEA Git 选项栏各项功能详解 如图所示 Copy Revision Number 顾名思义 拷贝当前版本号 到剪切板 a8e4b86ce9ca01968629504a6e19b4b99d76a853 Create Patch 在 git 日志中选择要创建补丁的commit&#xff0c;右键选择Create Patch...同一个文件在多次commit中都存在&#xff…

DSP-离散时间系统

目录 概念&#xff1a; 累加器(Accumulator)&#xff1a; N点滑动滤波器&#xff1a; 离散时间系统的分类 &#xff1a; 线性系统 Linear System 移不变系统 Shift-Invariant Systems 因果系统 Causal System 稳定系统 Stable System 无源&#xff08;passive&#x…

蚂蚁感冒(第五届蓝桥杯省赛C++A/B组)

目录 题目详细&#xff1a;​编辑 题目思路&#xff1a; 两种情况&#xff1a; 代码详解&#xff1a; 题目详细&#xff1a; 题目思路&#xff1a; 这个题目的关键在于对蚂蚁相遇 的时候情况的看待 两个蚂蚁相遇时候的情况 我们可以看作 他们相互穿过了彼此 假设相遇…

基于CNN的MINIST手写数字识别项目代码以及原理详解

文章目录项目简介项目开发软件环境项目开发硬件环境前言一、数据加载的作用二、Pytorch进行数据加载所需工具2.1 Dataset2.2 Dataloader2.3 Torchvision2.4 Torchtext2.5 加载项目需要使用的库三、加载MINIST数据集3.1 数据集简介3.2 数据预处理3.3 加载数据集四、模型构建五、…

【分布式技术专题】「架构实践于案例分析」总结和盘点目前常用分布式事务特别及问题分析(Seata-终)

分布式事务中间件对⽐与选择 tx-lcnEasyTransactionByteTCCSeata Seata实现分布式事务 我们主要以Seata的分布式事务框架进行介绍分析&#xff0c;相关的并且针对于其三种模式进行分别说明介绍。 搭建Seata Server 前往https://github.com/seata/seata/releases 下载Seata安装…

TCP通信

目录 一.服务端 1.1创建套接字与绑定 1.2监听 1.3服务端获取连接 1.4服务端提供服务 二.客户端 2.1创建套接字 2.2客户端获取连接 2.3客户端发送需求 三.填充命令行参数 3.1客户端 3.2服务端 3.3结果测试 四.线程版本服务端 4.1线程版 4.2线程池版 一.服务端 与上文…

程序员过圣诞 | 用HTML写出绽放的烟花

文章目录一、前言二、创意名三、效果展示四、烟花代码五、总结一、前言 2022年圣诞节到来啦&#xff0c;圣诞节是基督教纪念耶稣诞生的重要节日。亦称耶稣圣诞节、主降生节&#xff0c;天主教亦称耶稣圣诞瞻礼。耶稣诞生的日期&#xff0c;《圣经》并无记载。公元336年罗马教会…

【博客567】http/2 goaway frame 与 grpc graceful restart

http2 goway frame 与 grpc graceful restart 1、http/2 HTTP/2新增特性 二进制分帧(HTTP Frames)多路复用头部压缩服务端推送(server push)等等新特性 二进制分帧(HTTP Frames)是实现一流多用的基础 HTTP/2最革命性的原因就在于这个二进制分帧了&#xff0c;要了解二进制…

Win10 21H2 19044+vs2019 WDK驱动开发,错误 MSB8040缓解Spectre 漏洞的库以及输出SXS.DLL的垃圾信息

错误 MSB8040缓解Spectre 漏洞的库以及输出SXS.DLL的垃圾信息&#xff0c;win7关闭驱动签名、进入驱动测试模式缓解Spectre 漏洞错误的解决windbg狂刷输出SXS.DLL的垃圾信息的解决缓解Spectre 漏洞错误的解决 在工程配置属性&#xff0c;常规&#xff0c;输出目录&#xff0c;…

SSD_学习笔记记录

one-steage VGG16模型的修改 VGG16的模型输出&#xff0c;其中224.。。为特征图的大小。 SSD模型中对VGG网络的修改&#xff1a; SSD模型是对VGG中的第四个卷积块中的最后一个Conv2d进行第一个输出&#xff0c;在这里简称为Conv4-3。以及第五个卷积块中的最后一个Conv2d进行…

TCP 的可靠传输(计算机网络-运输层)

TCP的可靠传输 因特网的网络层服务是不可靠的 TCP在IP的不可靠的&#xff1a;尽最大努力服务的基础上实现了一种可靠的数据传输服务 TCP采用的可靠传输机制&#xff1a;差错检测、序号、确认、超时重传、滑动窗口等 互联网环境中端到端的时延往往是比较大的&#xff1a;采用…

(机器学习深度学习常用库、框架|Pytorch篇)第二节:Pytorch中数据加载方法(DataLoader、DataSet和Sampler)

文章目录一&#xff1a;DataLoader,、DataSet、Sampler三者的关系二&#xff1a;DataLoader,、DataSet、Sampler详解&#xff08;1&#xff09;DatasetA&#xff1a;基本介绍C&#xff1a;Pytroch内置数据集&#xff08;2&#xff09;SamplerA&#xff1a;SequentialSampler&am…

【算法与数据结构】排序详解(C语言)

目录 前言 插入排序 希尔排序 选择排序 堆排序 冒泡排序 快速排序 hoare版本 ​编辑 挖坑法 前后指针版本 优化 非递归实现 归并排序 非递归实现 前言 &#x1f384;在生活中我们必不可少的就是对一组数据进行排序&#xff0c;所谓排序&#xff0c;就是使一串…

ByteBuffer常用方法与分析

目录 目标 常用API 工具方法 演示案例 allocate(int capacity)和allocateDirect(int capacity) put()和get() flip()和hasRemaining() clear() compact() wrap() 总结 目标 掌握ByteBuffer常用方法&#xff0c;分析ByteBuffer对象在切换读写模式的情况下基本属性的变…

【REDIS】安装配置 可视化工具

Redis作为一个高性能&#xff0c;内存可存储化的no SQL数据库&#xff0c;近两年来发展迅猛&#xff0c;然而并没有比较成熟的管理工具来使用&#xff0c;或者是我不知道 下载redis 并安装&#xff1a; 双击安装&#xff0c;可以安装到d: 盘 配置文件是 .conf Redis作为一个…

排序——快排(递归/非递归)

目录 定义 递归 三种方法 1.hoare法 2.挖坑法 3.双指针法 整体 优化1 优化2 非递归 定义 快速排序是Hoare于1962年提出的一种二叉树结构的交换排序方法&#xff0c;其基本思想为&#xff1a;任取待排序元素序列中 的某元素作为基准值&#xff0c;按照该排序码将待排序集…