锁之间的故事

目录

常用锁策略

1.乐观锁 VS 悲观锁

2.轻量级锁 VS 重量级锁

3.自旋锁 VS 挂起等待锁

4.互斥锁 VS 读写锁

5.公平锁 VS 非公平锁

6.可重入锁 VS 可重入锁

CAS

ABA问题

Synchronized原理

1. 锁升级/锁膨胀

2.锁消除

3.锁粗化


常用锁策略

1.乐观锁 VS 悲观锁

站在锁冲突概率的预测角度.乐观锁预测冲突概率较小,悲观锁预测锁冲突概率较大

synchronized既是一个悲观锁,也是一个乐观锁.它默认是一个乐观锁,但当锁竞争比较激烈,就会变成悲观锁.

2.轻量级锁 VS 重量级锁

站在加锁操作的开销角度. 轻量级锁开销较小,重量级锁开销较大.

synchronized默认是一个轻量级锁,但发现锁竞争比较激烈的时候就会转转换成重量级锁.

3.自旋锁 VS 挂起等待锁

自旋锁是一种典型的轻量级锁,对于自旋锁,当锁被释放后,线程能第一时间感知到锁,从而有机会获取到锁

挂起等待锁是一种典型的重量级锁.当锁被释放后,继续等待,不知道什么时候能过获取到锁

synchronized这里的轻量级锁是基于自旋锁的方式实现的,而synchronized的重量级锁是针对挂起等待锁的方式实现的.

4.互斥锁 VS 读写锁

互斥锁提供加锁和解锁两种操作,如果一个线程加锁,另外一个线程也尝试加锁,就会产生阻塞等待.

读写锁提供了三种操作,分别是针对读操作加锁,针对写操作加锁和解锁操作.多线程针对同一个变量并发读,这个时候没有线程安全问题,也不需要加锁控制.

读锁和读锁之间没有互斥,写锁和写锁之间存在互斥,写锁和读锁之间存在互斥.

 synchronized不是读写锁

5.公平锁 VS 非公平锁

所谓公平,就是指 " 先来后到 ",下面举个栗子

 公平锁: 当女神分手后,由等待队列中最早来的舔狗上

 非公平锁: 就是当女神分手后,三个滑稽老铁都有了追求女神的机会,而和之前追了多长时间没有关系.

在操作系统和 Java synchronized 中都是非公平锁,操作系统针对加锁的控制,本身依赖线程的调度顺序,这个调度顺序是随机的,不会考虑线程等待了多长时间.

6.可重入锁 VS 可重入锁

不可重入锁: 一个线程针对一把锁,连续加锁两次出现死锁

可重入锁: 一个线程针对一把锁,连续加锁多次都不会死锁.

synchronized是可重入锁.

关于可重入问题和synchronized的相关操作

CAS

CAS指的是 compare and swap指的是 比较并交换,一个CAS涉及到一下操作:

上述这个CAS过程并非是通过异端代码实现的,而是通过一条 CPU指令完成的.而CAS操作是原子的,在一定程度上就回避了线程安全问题,同时在解决线程安全问题除了加锁之外,又可以使用CAS方法了.

CAS相当于通过一个原子的操作 , 同时完成 " 读取内存 , 比 较是否相等, 修改内存 " 这三个步骤 .

CAS可以实现原子类,在Java标准库中提供的类 

接下来用原子类写一个两个线程并发自加的操作

import java.util.concurrent.atomic.AtomicInteger;

    public static void main(String[] args) {
        //这些原子类,就是基于 CAS 实现了 自增,自减等操作
        //此时进行这类操作不用加锁也是线程安全的
        AtomicInteger count = new AtomicInteger(0);
        Thread t1 = new Thread(()-> {
            for (int i = 0; i < 50000; i++) {
                count.getAndIncrement();  //count++
                // count.incrementAndGet();  //++count
                // count.getAndDecrement();  //count--
                // count.decrementAndGet();  //count--
            }
        });
        Thread t2 = new Thread(()-> {
            for (int i = 0; i < 50000; i++) {
                count.getAndIncrement();  //count++
            }
        });
        t1.start();
        t2.start();
        try {
            t1.join();
            t2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(count.get());

    }

上面操作用伪代码进行实现

原子类这里的实现,每次修改之前,在确认一下这个值是否符合要求.

CAS还可以实现自旋锁

接下来看看CAS实现的自旋锁的伪代码

注意: 在java中并没有提供CAS方法,此处CAS相当于是一个简化的方式

ABA问题

CAS在运行中的核心是检查value和oldValue是否一致,如果一致,就视为value中途没有被修改过,在进行下一步操作,但可能在检查value和oldValue是否一致之前,可能会出现value从A修改成B,又从B修改为A这样的操作,CAS无法判断这种操作是否发生,这样的问题就叫ABA问题

针对这样的问题,采取的方案就是给要修改的数据加版本号,想象初始版本号是1,每次修改版本号都+1,人后进行CAS的时候,不是一以金额为基准了,而是以版本号为基准,因为版本号是只会自加的,而不会减少.

Synchronized原理

前面提到过,synchronized关键字,两个线程针对同一个线程加锁,就会产生阻塞等待.但在synchronized内部还有一些优化机制,存在的目的就是为了让锁更高效.

1. 锁升级/锁膨胀

通过Synchronized关键字进行加锁的的过程中,Synchronized会经历,无锁,偏向锁,轻量级锁,和重量级锁四种状态.

        第一个尝试加锁的线程,优先进入偏向锁的状态.

偏向锁不是真的 " 加锁 ", 只是给对象做一个 " 偏向锁的标记 ", 记录这个锁属于哪个线程 .
如果后续没有其他线程来竞争该锁 , 那么就不用进行其他同步操作了 ( 避免了加锁解锁的开销 )
如果后续有其他线程来竞争该锁 ( 刚才已经在锁对象中记录了当前锁属于哪个线程了 , 很容易识别 当前申请锁的线程是不是之前记录的线程), 那就取消原来的偏向锁状态 , 进入一般的轻量级锁状态 .
偏向锁本质上相当于 " 延迟加锁 " . 能不加锁就不加锁 , 尽量来避免不必要的加锁开销 .
但是该做的标记还是得做的 , 否则无法区分何时需要真正加锁 .
        当synchronized发生锁竞争的时候就会从偏向锁升级成轻量级锁,此时,synchronized相当于通过自旋的方式,来进行加锁的.(和上面CAS讲的伪代码一样).
        如果竞争进一步加强,自旋锁不能获取到当前锁状态,就会进入重量级锁.重量级锁是操作系统内核原生的API实现的,此时这个加锁功能就会影响到 线程的调度.如果线程进入重量级加锁,并且发生锁竞争,此时线程会被放到阻塞队列里,暂时不参与调度,直到锁被释放,才有机会被调度,并重新获取到锁.

2.锁消除

编译器智能的判定,看当前的代码是否真的要加锁,如果这个场景不需要加锁,而我们加了,编译器聚会自动把锁干掉.

3.锁粗化

锁的粒度: synchronized 包含的代码越多,粒度就越粗,包含的代码越少,粒度就越细.

通常情况下,认为锁的粒度细一点比较好,因为加锁部分的代码,是不能并发执行的,锁的粒度越细,能并发执行的代码就越多;反之,就越少.

但也有特殊的情况,有时候可能没有现成来抢占这个锁,jvm就会自动把锁粗化,避免频繁申请释放锁.

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

二叉树相关

一、概念 二、题目 2.1 把数组转换成二叉树 2.2.1 使用队列方式 public static Node getTreeFromArr2(int[] arr) {if (arr null || arr.length 0) {return null;}LinkedList<Node> quque new LinkedList<>();Node root new Node(arr[0]);quque.add(root);in…

有大量虾皮买家号想防关联该怎么做?

Shopee平台规定一个买家只能拥有一个买家号&#xff0c;如果一台电脑或者一个手机同时登录好几个买家号&#xff0c;那么很有可能就会关联封号的。那么有大量虾皮买家号想防关联该怎么做&#xff1f; 如果想要运用大量的shopee买家号来操作&#xff0c;那么需要使用有防指纹技术…

利用vscode连接远程服务器进行代码调试

文章目录 一、vscode下载二、连接服务器1. 安装remote development套件2. 配置ssh3. 连接服务器4. 打开服务器文件路径 三、支持GUI显示1. windows系统安装xserver服务&#xff1a;可以用xming或VcXsrv2. windows系统(安装了vscode的系统)下安装插件3. vscode实现免密登录远程服…

<蓝桥杯软件赛>零基础备赛20周--第6周--数组和队列

报名明年4月蓝桥杯软件赛的同学们&#xff0c;如果你是大一零基础&#xff0c;目前懵懂中&#xff0c;不知该怎么办&#xff0c;可以看看本博客系列&#xff1a;备赛20周合集 20周的完整安排请点击&#xff1a;20周计划 每周发1个博客&#xff0c;共20周&#xff08;读者可以按…

Ansys Speos | 如何利用Speos联合optiSLang进行光导优化设计

在本例中&#xff0c;我们将使用 Speos 和 optiSLang 实现光导的设计优化&#xff0c;以实现汽车日行灯、内饰氛围灯等的光导设计&#xff0c;并改善光导亮度的均匀性&#xff0c;以自动优化设计的方式实现更好的照明外观。 概述 在汽车照明应用中&#xff0c;日行灯是一个独特…

[文件读取]Grafana未授权任意文件读取

1.1漏洞描述 漏洞编号Grafana未授权任意文件读取漏洞类型文件读取漏洞等级⭐⭐⭐漏洞环境VULFOCUS攻击方式 描述: Grafana是一个跨平台、开源的数据可视化网络应用程序平台。用户配置连接的数据源之后&#xff0c;Grafana可以在网络浏览器里显示数据图表和警告。 Grafana 存在…

【自定义列表头】vue el-table表格自定义列显示隐藏,多级表头自定义列显示隐藏,自由搭配版本和固定列版本【注释详细】

前言 功能介绍 最近遇到一个功能&#xff0c;需要的是把表格的列可以配置&#xff0c; 用户可以根据自己想要看的数据来改变表头列显示哪些隐藏哪些。 于是我做了两个版本。第一个版本是自由搭配的。 就是提前顶号所有的列&#xff0c;然后自己可以拖拽到想要位置顺序。 也可以…

打开IE浏览器

原文地址&#xff1a;https://www.xiaoheiwoo.com/windows-11-internet-explorer/#:~:text%E5%A6%82%E4%BD%95%E5%9C%A8%20Windows11%20%E4%B8%AD%E5%90%AF%E7%94%A8%20IE%E6%B5%8F%E8%A7%88%E5%99%A8%E7%9A%843%E7%A7%8D%E6%96%B9%E6%B3%95%201%20%E6%96%B9%E6%B3%95%E4%B8%80…

俄罗斯方块

一.准备工作 先创建一个新的Java项目命名为“俄罗斯方块”。再在该项目中创建一个文件夹命名为”images”&#xff0c;并将所需的图片素材拖入该文件夹。 二.代码呈现 编写小方块类&#xff1a; import java.awt.image.BufferedImage;/*** 描述:小方块类* 属性&#xff1a;…

Nas搭建webdav服务器并同步Zotero科研文献

无需云盘&#xff0c;不限流量实现Zotero跨平台同步&#xff1a;内网穿透私有WebDAV服务器 文章目录 无需云盘&#xff0c;不限流量实现Zotero跨平台同步&#xff1a;内网穿透私有WebDAV服务器一、Zotero安装教程二、群晖NAS WebDAV设置三、Zotero设置四、使用公网地址同步Zote…

不会代码的时候,如何使用Jmeter完成接口测试?

1.接口测试简介 接口测试是测试系统组件间接口的一种测试。接口测试主要用于检测外部系统与系统之间以及内部各个子系统之间的交互点。测试的重点是要检查数据的交换&#xff0c;传递和控制管理过程&#xff0c;以及系统间的相互逻辑依赖关系等。 2.接口测试流程 接口测试…

推荐一个非常好用的uniapp的组件库【TMUI3.0】

文章目录 前言官网地址如何使用&#xff1f;注意事项后言 前言 hello world欢迎来到前端的新世界 &#x1f61c;当前文章系列专栏&#xff1a;前端系列文章 &#x1f431;‍&#x1f453;博主在前端领域还有很多知识和技术需要掌握&#xff0c;正在不断努力填补技术短板。(如果…

Java虚拟机运行时数据区结构详解

Java虚拟机运行时数据区结构如图所示 程序计数器 程序计数器&#xff08;Program Counter Register&#xff09;是一块较小的内存空间&#xff0c;它可以看作是当前线程所执行的字节码的行号指示器。 多线程切换时&#xff0c;为了能恢复到正确的执行位置&#xff0c;每条线程…

[Python学习笔记]Python 性能分析

在上一章节 [Python学习笔记]Requests性能优化之Session 中&#xff0c;通过在 Resquests 中使用 session&#xff0c;将 Python 脚本的运行效率提升了 3 倍。但当时对问题的排查主要是基于程序实现逻辑的推断&#xff0c;并没有实质性的证据。 本次使用 Python 的性能分析工具…

【每日一题】最长奇偶子数组

文章目录 Tag题目来源解题思路方法一&#xff1a;枚举方法二&#xff1a;一次遍历 其他语言python3 写在最后 Tag 【一次遍历】【枚举】【数组】【2023-11-16】 题目来源 2760. 最长奇偶子数组 解题思路 方法一&#xff1a;枚举 本题有多种方法可以解决&#xff0c;最朴素的…

如何有效防止公司内部的信息泄露?

信息泄露对公司可能带来严重影响&#xff0c;因此采取一系列措施以确保信息安全至关重要。以下是一些建议&#xff1a; 部署综合的防泄密软件&#xff1a; 在公司内部&#xff0c;使用专业的防泄密软件如华企盾DSC系统&#xff0c;涵盖文件加密、U盘管控、桌面行为管理、日志审…

极智AI | Realtime Multi-Person人体姿态估计之OpenPose

欢迎关注我的公众号 [极智视界],获取我的更多经验分享 大家好,我是极智视界,本文来介绍一下 Realtime Multi-Person人体姿态估计之OpenPose。 邀您加入我的知识星球「极智视界」,星球内有超多好玩的项目实战源码下载,链接:https://t.zsxq.com/0aiNxERDq OpenPose 主要是…

qt使用AES加密、解密字符串

一、AES算法 AES (Advanced Encryption Standard) 是一种对称加密算法&#xff0c;是目前被广泛使用的数据加密标准之一。该算法旨在取代DES (Data Encryption Standard) 算法。AES最初由比利时密码学家 Joan Daemen 和 Vincent Rijmen 提出&#xff0c;经过多年的演化、改进和…

TSINGSEE青犀智慧机房AI+视频智能监管方案,保障机房设备稳定运转

一、背景与需求分析 随着互联网的高速发展&#xff0c;机房数量及配套环境设备日益增多&#xff0c;其运行状况直接决定着企业组织的运营效率和服务质量。作为企业信息化的核心&#xff0c;机房的安全监测与管理&#xff0c;不仅关系到企业的稳定运转&#xff0c;同时也关系到…

jffs2文件系统(二)

本篇文章讲解一下如何制作jffs2文件系统&#xff0c;以及如何在linux下把jffs2作为根文件系统使用。 文件系统制作 制作工具&#xff1a;mtd_utils&#xff0c;可以自己安装 mkfs.jffs2 -o root-uclibc-jffs2 -r root-uclibc -e 0x10000 -s 0x1000 -n -l -X zlib --pad0x10000…