深入理解锁

目录

常用锁策略

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/153768.html

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

相关文章

自建es数据迁移阿里云方案

一、ElasticSearch数据迁移方法介绍 https://help.aliyun.com/document_detail/170095.html?spma2c4g.26937906.0.0.429240c9ymiXGm 可以通过Logstash、reindex和OSS等多种方式完成阿里云Elasticsearch间数据迁移、Elasticsearch数据迁移至Openstore存储中、自建Elasticsear…

教你轻松保存视频号里的视频到相册

在今天的数字化社会&#xff0c;人们在各种社交平台上分享视频已经成为一种习惯。而在短视频平台上&#xff0c;用户可以轻松地上传、分享和观看各种内容丰富的视频。然而&#xff0c;很多用户在观看完善了的视频后&#xff0c;希望将喜欢的视频保存到手机相册中&#xff0c;以…

yyds!这个写文案神器爱了爱了

每次写文案都绞尽脑汁&#xff0c;不知道怎么写&#xff0c;想了很久&#xff0c;好不容易写完了&#xff0c;数据真的很差&#xff0c; 心累啊&#xff0c;家人们&#xff01;&#xff01; 只要输入你想写的标题&#xff0c;马上就能得到一篇&#xff0c;不满意就重写&#…

力扣-路径总和问题

路径总和 --简单 112. 路径总和 给你二叉树的根节点 root 和一个表示目标和的整数 targetSum 。判断该树中是否存在 根节点到叶子节点 的路径&#xff0c;这条路径上所有节点值相加等于目标和 targetSum 。如果存在&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 f…

MATLAB中zticks函数用法

目录 语法 说明 示例 指定 z 轴刻度值和标签 指定非均匀 z 轴刻度值 以 2 为增量递增 z 轴刻度值 将 z 轴刻度值设置回默认值 指定特定坐标区的 z 轴刻度值 删除 z 轴刻度线 zticks函数的功能是设置或查询 z 轴刻度值。 语法 zticks(ticks) zt zticks zticks(auto)…

猫罐头哪个牌子好性价比高?5款良心性价比的猫罐头推荐给新手养猫!

养猫新手很容易陷入疯狂购买的模式&#xff0c;但有些品牌真的不能乱买&#xff01;现在的市场环境不太好&#xff0c;我们需要学会控制自己的消费欲望&#xff0c;把钱花在刀刃上&#xff01;宠物市场真的很内卷&#xff0c;很多品牌都在比拼产品的数据和营养成分。很多铲屎官…

qt Rectangle 使用Gradient设置渐变方向 制作渐变进度条

1.Gradient方向可查看官网 Gradient.Horizontala horizontal gradient Gradient.Verticala vertical gradient ​​ ProgressBar {id: batteryvalue: 0.5width: 150height: 20anchors.centerIn: parentbackground: Rectangle {implicitWidth: battery.widthimplicitHeight:…

python+appium自动化测试如何控制App的启动和退出

由于本人使用的是Android设备做自动化测试&#xff0c;所以以下内容均基于Android系统做出的整理 一、启动app 启动app需要设置Capability参数&#xff0c;而Capability参数放在Desired Capalibity中&#xff0c;Desired Capalibity告诉Appium想要的自动化平台和应用程序&…

AI自动直播软件,ai无人直播工具2.0支持多平台矩阵直播一键同步直播脚本内容【直播脚本+使用技术教程】

AI实景直播软件简介&#xff1a; 支持一台手机自动直播&#xff0c;支持语音和文字同时回复&#xff0c;商品自动弹窗&#xff0c;支持抖音、快手、视频号、美团平台直播&#xff0c;支持矩阵直播&#xff0c;一键同步直播脚本内容。 设备需求&#xff1a; 安卓手机&#xf…

python连接redis库

在自动化过程中&#xff0c;如果需要动态获取某个数据时&#xff0c;需要连接redis数据库。下面来详细介绍下如何操作。 redis这个库是python自带的&#xff0c;直接import导入即可,如下; import redis 1. redis 地址和端口&#xff0c;端口一般都是默认的6379,只需要换下地…

VS2017的redis客户端实现

VS2017下Redis服务器源码地址 https://download.csdn.net/download/qq_23350817/88541316 VS2017下Redis客户端源码地址(hiredis已完成windows下编译)&#xff1a; https://download.csdn.net/download/qq_23350817/88541242 C代码实现&#xff1a; #include <stdio.h>…

【Maven教程】(十一):使用 Maven 构建 Web应用 —— 使用 jetty-maven-plugin 进行测试、使用 Cargo 实现自动化部署~

Maven 使用 Maven 构建 Web应用 1️⃣ Web 项目的目录结构2️⃣ account-service2.1 account-service的 POM2.2 account-service 的主代码 3️⃣ account-web3.1 account-web 的POM3.2 account-web 的主代码 4️⃣ 使用 jetty-maven-plugin 进行测试5️⃣ 使用 Cargo 实现自动…

【文件上传】01ctfer 文件上传获取flag

1.1漏洞描述 漏洞名称01ctfer 文件上传漏洞类型文件上传漏洞等级⭐⭐⭐漏洞环境docker攻击方式 1.2漏洞等级 高危 1.3影响版本 暂无 1.4漏洞复现 1.4.1.基础环境 靶场docker工具BurpSuite 1.4.2.环境搭建 1.创建docker-compose.yml文件 version: 3.2 services: upload: …

Banana Pi BPI-W3之RK3588安装Qt+opencv+采集摄像头画面.

场景&#xff1a;在Banana Pi BPI-W3 RK3588上做qt开发工作RK3588安装Qtopencv采集摄像头画面 2. 环境介绍 硬件环境&#xff1a; Banana Pi BPI-W3RK3588开发板、MIPI-CSI摄像头( ArmSoM官方配件 )软件版本&#xff1a; OS&#xff1a;ArmSoM-W3 Debian11 QT&#xff1a;QT5…

Compose学习之绘制速度表盘

内心想法XX compose已经发布好久了&#xff0c;还没有用过compose写过UI&#xff0c;之前只是在官网上了解过&#xff0c;看着这可组合函数嵌套&#xff0c;我就脑袋大&#xff0c;更Flutter一个德行&#xff0c;我的内心是抵触的&#xff0c;还是觉得用XML写香&#xff0c;抱…

广州华锐互动:办税服务厅税务登记VR仿真体验让税务办理更加灵活高效

在数字化世界的今天&#xff0c;我们正在见证各种业务过程的转型&#xff0c;而税务办理也不例外。最近&#xff0c;一种全新的交互方式正在改变我们处理税务的方式&#xff1a;虚拟现实&#xff08;VR&#xff09;。 首先&#xff0c;用户需要戴上虚拟现实头显&#xff0c;然后…

Antv/G2 柱状图添加自定义点击事件

<!DOCTYPE html> <html><head><meta charset"UTF-8"><title>柱状图点击事件</title></head><body><div id"container" /><script src"https://gw.alipayobjects.com/os/lib/antv/g2/4.2.8/…

每日一练 | 华为认证真题练习Day131

1、某台路由器输出信息如下&#xff0c;下列说法正确的有&#xff1f;&#xff08;多选&#xff09; A. 本路由器是DR B. 路由器Router ID为10.0.1.1 C. 路由器Router ID为10.0.2.2 D. 本路由器的接口地址为10.0.12.2 2、以下那条命令可以开启路由器接口的DHCP中继功能&…

TS7031: Binding element ‘role‘ implicitly has an ‘any‘ type.

文章 前言错误场景问题分析解决方案后言 前言 ✨✨ 他们是天生勇敢的开发者&#xff0c;我们创造bug&#xff0c;传播bug&#xff0c;毫不留情地消灭bug&#xff0c;在这个过程中我们创造了很多bug以供娱乐。 前端bug这里是博主总结的一些前端的bug以及解决方案&#xff0c;感兴…

就近值 reduce用法 时间戳与时间点对比循环查找

后台接口返回的13为时间戳 需要与数据data的time做对比&#xff0c;查找出最近的值 data的数据结构如下&#xff1a; 将&#xff1a;改为空格&#xff0c;变成数字之间的对比 //查找最近的时间getNearestTime(timestamp, data) {let date new Date(timestamp)let h date.ge…