【JAVAEE】常见的锁策略

news2024/11/24 1:55:47

目录

1.常见的锁

1.乐观锁&悲观锁

2.轻量级锁&重量级锁

3.读写锁&普通互斥锁

4.自旋锁&挂起等待锁

5.可重入锁&不可重入锁

6.公平锁&非公平锁

2.CAS

1.什么是CAS

2.CAS的应用

1.实现原子类

2.实现自旋锁

3.synchronized用到的锁策略

1.synchronized实现的锁策略

2.加锁的工作过程

3.一些优化操作

1.锁消除

2.锁粗化


1.常见的锁

1.乐观锁&悲观锁

乐观锁:对运行环境持乐观态度,刚开始不加锁,当有竞争的时候再去加锁

悲观锁:对运行环境持悲观态,刚开始就直接加锁

举个例子:

同学 A 认为 " 老师是比较忙的 , 我来问问题 , 老师不一定有空解答 ". 因此同学 A 会先给老师发消息 : " 老师你忙嘛 ? 我下午两点能来找你问个问题嘛 ?" ( 相当于加锁操作 ) 得到肯定的答复之后 , 才会真的来问问题 . 如果得到了否定的答复 , 那就等一段时间 , 下次再来和老师确定时间 . 这个是悲观锁 .
同学 B 认为 " 老师是比较闲的 , 我来问问题 , 老师大概率是有空解答的 ". 因此同学 B 直接就来找老师 .( 没加锁 , 直接访问资源 ) 如果老师确实比较闲 , 那么直接问题就解决了 . 如果老师这会确实很忙 , 那么同学 B 也不会打扰老师 , 就下次再来 ( 虽然没加锁 , 但是能识别出数据访问冲突 ). 这个是乐观锁 .

2.轻量级锁&重量级锁

轻量级锁:可以是纯用户态的锁,消耗的资源比较小

重量级锁:可能会调用到系统的内核态,消耗的资源比较多。

锁的核心特性 " 原子性 ", 这样的机制追根溯源是 CPU 这样的硬件设备提供的 .
  • CPU 提供了 "原子操作指令".
  • 操作系统基于 CPU 的原子指令, 实现了 mutex 互斥锁.
  • JVM 基于操作系统提供的互斥锁, 实现了 synchronized ReentrantLock 等关键字和类.
重量级锁 : 加锁机制重度依赖了 OS 提供了 mutex
  • 大量的内核态用户态切换
  • 很容易引发线程的调度
这两个操作 , 成本比较高 . 一旦涉及到用户态和内核态的切换 , 就意味着 " 沧海桑田 ".
轻量级锁 : 加锁机制尽可能不使用 mutex, 而是尽量在用户态代码完成 . 实在搞不定了 , 再使用 mutex.
  • 少量的内核态用户态切换.
  • 不太容易引发线程调度

3.读写锁&普通互斥锁

读锁:共享锁,读与读可以同时拿到锁资源

写锁:排他锁,不能同时写写,写读或者读写

普通互斥锁:synchronized,只能有一个线程拿到锁资源,其它的要参与锁竞争,没有竞争到锁的时候就要阻塞等待。

多线程之间,数据的读取方之间不会产生线程安全问题,但数据的写入方互相之间以及和读者之间都需要进行互斥。如果两种场景下都用同一个锁,就会产生极大的性能损耗。所以读写锁因此而产生 。
举个例子:
比如教务系统 .
每节课老师都要使用教务系统点名 , 点名就需要查看班级的同学列表 ( 读操作 ). 这个操作可能要每周 执行好几次 .而什么时候修改同学列表呢 ( 写操作 )? 就新同学加入的时候 . 可能一个月都不必改一次 .

4.自旋锁&挂起等待锁

自旋锁:不停的询问资源是否被释放,如果释放了第一时间可以获得锁资源

挂起等待锁:等待通知之后再去竞争锁,并不会第一时间获取到锁资源

举个例子:

 自旋锁是一种典型的 轻量级锁 的实现方式.

优点 : 没有放弃 CPU, 不涉及线程阻塞和调度 , 一旦锁被释放 , 就能第一时间获取到锁 .
缺点 : 如果锁被其他线程持有的时间比较久 , 那么就会持续的消耗 CPU 资源 . ( 而挂起等待的时候是 不消耗 CPU )

5.可重入锁&不可重入锁

可重入锁:对于同一个锁对象可以加多次锁

不可重入锁:不能对同一个锁对象加多次锁

6.公平锁&非公平锁

公平锁:先排队等待的线程先获取到锁资源

非公平锁:没有先来后到的说法,谁抢到就是谁的

2.CAS

1.什么是CAS

CAS:全程Compare and swap,字面意思“比较并交换”,一个CAS涉及到以下操作:

我们假设内存中的原数据V,旧的预期值A,需要修改的新值B

1.比较A与V是否相等(比较)

2.如果比较相等,将B写入V(交换)

3.返回操作是否成功

CAS伪代码(工作流程):

boolean CAS(address, expectValue, swapValue) {
 if (&address == expectedValue) {
   &address = swapValue;
        return true;
   }
    return false;
}

用期望值与内存中的值比较,如果内存中的值与期望值相等,那么用swapValue覆盖内存中的值,如果期望值与内存中的值不等那么什么也不做。

2.CAS的应用

1.实现原子类

标准库中提供了 java.util.concurrent.atomic , 里面的类都是基于这种方式来实现的 。典型的就是 AtomicInteger .。 其中的 getAndIncrement 相当于 i++ 操作 .。
AtomicInteger atomicInteger = new AtomicInteger(0);
// 相当于 i++
atomicInteger.getAndIncrement();

伪代码实现:

class AtomicInteger {
    private int value;
    public int getAndIncrement() {
        int oldValue = value;
        while ( CAS(value, oldValue, oldValue+1) != true) {
            oldValue = value;
       }
        return oldValue;
   }
}

假设两个线程同时调用getAndIncrement。

(1).两个线程都读取value的值到oldvalue中。

 (2).线程1先执行CAS操作,由于oldvalue和value值相同,直接对value进行赋值

注意 :
CAS 是直接读写内存的 , 而不是操作寄存器 .
CAS 的读内存 , 比较 , 写内存操作是一条硬件指令 , 是原子的 .

 (3)线程2再执行CAS操作,第一次CAS的时候发现oldvalue和value不相等,不能赋值,因此进入循环。在循环中重新读取value的值赋给oldvalue

 (4)线程2接下来第二次执行CAS,此时oldvalue和value相等,于是直接进行赋值操作

 (5)线程1和线程2返回各自oldvalue值即可。

通过形如上述代码就可以实现一个原子类 . 不需要使用重量级锁 , 就可以高效的完成多线程的自增操作。

2.实现自旋锁

自旋锁伪代码:

public class SpinLock {
    private Thread owner = null;
    public void lock(){
        // 通过 CAS 看当前锁是否被某个线程持有. 
        // 如果这个锁已经被别的线程持有, 那么就自旋等待. 
        // 如果这个锁没有被别的线程持有, 那么就把 owner 设为当前尝试加锁的线程. 
        while(!CAS(this.owner, null, Thread.currentThread())){
       }
   }
    public void unlock (){
        this.owner = null;
   }
}

3.synchronized用到的锁策略

通过以上的锁策略可以知道,synchronized在不同的时期可能会用到不同的锁策略。

1.synchronized实现的锁策略

①既是乐观锁也是悲观锁

②既是轻量级锁也是重量级锁

  • 轻量级锁是基于自旋锁实现的
  • 重量级锁是基于挂起等待锁实现的

③是普通互斥锁

④既是自旋锁也是挂起等待锁

⑤是可重入锁

⑥是非公平锁

1. 开始时是乐观锁 , 如果锁冲突频繁 , 就转换为悲观锁 .
2. 开始是轻量级锁实现 , 如果锁被持有的时间较长 , 就转换成重量级锁 .
3. 实现轻量级锁的时候大概率用到的自旋锁策略

2.加锁的工作过程

 ①偏向锁

第一个进行加锁的线程,优先进入偏向锁状态。

偏向锁不是真的 " 加锁 ", 只是给对象头中做一个 " 偏向锁的 标记 ", 记录这个锁属于哪个线程 .
如果后续没有其他线程来竞争该锁 , 那么就不用进行其他同步操作了 ( 避免了加锁解锁的开销 )
如果后续有其他线程来竞争该锁 ( 刚才已经在锁对象中记录了当前锁属于哪个线程了 , 很容易识别当前申请锁的线程是不是之前记录的线程 ), 那就取消原来的偏向锁状态 , 进入一般的轻量级锁状态 .
偏向锁本质上相当于 " 延迟加锁 " . 能不加锁就不加锁 , 尽量来避免不必要的加锁开销 .
但是该做的标记还是得做的 , 否则无法区分何时需要真正加锁 .

②轻量级锁

随着其它线程进入竞争,偏向锁状态被消除,进入轻量级锁状态(自适应的自旋锁)。此时的轻量级锁就是通过CAS来实现的。

  • 通过 CAS 检查并更新一块内存 (比如 null => 该线程引用)
  • 如果更新成功, 则认为加锁成功
  • 如果更新失败, 则认为锁被占用, 继续自旋式的等待(并不放弃 CPU).
自旋操作是一直让 CPU 空转 , 比较浪费 CPU 资源 .
因此此处的自旋不会一直持续进行 , 而是达到一定的时间 / 重试次数 , 就不再自旋了 .
也就是所谓的 " 自适应 "
③重量级锁
如果竞争进一步激烈,自旋不能快速获取到锁状态,就会膨胀为重量级锁。

3.一些优化操作

1.锁消除

在写代码时,程序会加入synchronized来保证线程安全。

如果加了synchronized的代码块中,只有读操作没有写操作,JVM就认为这个代码块没有必要加锁,JVM运行的时候就会被优化掉,这个现象叫做锁消除

2.锁粗化

一段逻辑中如果出现多次加锁解锁,编译器+JVM会自动进行锁的粗化。

执行一个业务逻辑发生了四次锁竞争,在保证程序正确的情况下,JVM会做出优化,只加一次锁,整个逻辑执行完后再释放,从而提高效率。

举个例子:

滑稽老哥当了领导 , 给下属交代工作任务 :
方式一 :
打电话 , 交代任务 1, 挂电话 .
打电话 , 交代任务 2, 挂电话 .
打电话 , 交代任务 3, 挂电话 .
方式二 :
打电话 , 交代任务 1, 任务 2, 任务 3, 挂电话 .
显然 , 方式二是更高效的方案 .

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

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

相关文章

RobotFramework +appium实现Android自动化

环境准备 1、已安装python37版本(SDK、JDK均已安装完成,且环境变量都配置好了)。 2、已安装robotframework。 3、已安装安卓模拟器(本文使用夜神模拟器)。 4、安装appium(下载地址:http://6…

立创梁山派学习笔记——GPIO输出控制

梁山派 前言开发板简介GD32F407ZGT6官方资源数据手册1.系统框图2. 引脚复用表3.命名规则4.其他 用户手册固件库与PACK包 开发环境搭建立创官方的资料包资料齐活,开发1.工程搭建2.使用寄存器点亮LEDGPIO数量LED的GPIO口GPIO的配置流程GPIO的寄存器1.端口控制寄存器&a…

假如你是一位测试主管,如何判断一名测试工程师是否优秀?

假如你是一位测试主管,去评价一名测试工程师是否优秀,那么你将如何去判断呢?你最看重的是哪方面的能力呢? 对于这个问题,是不能一概而论的,要分为两种情况,情况不同,答案一定是不同…

自媒体素材哪里找?这5个网站告诉你答案。

做自媒体最需要的就是各种视频、配乐、图片等素材了。想要图文好,那就必须要一个好封面图。想要视频好,那就必须要有好的素材和配乐。 那要如何找到这些素材?看这几个网站就够了。 1、菜鸟图库 https://www.sucai999.com/video.html?vNTY…

基于Kubernetes集群构建大中型企业CICD应用平台(1)-- devOps

一、DevOps介绍 软件开发最开始是由两个团队组成: 开发计划由开发团队从头开始设计和整体系统的构建。需要系统不停的迭代更新。 运维团队将开发团队的Code进行测试后部署上线。希望系统稳定安全运行。 这看似两个目标不同的团队需要协同完成一个软件的开发。 …

【游戏逆向】《创世战车》玩家遍历分析

对于这种FPS游戏来说,玩家的血量并不是很关键,不过想分析玩家对象内的其他信息,还是要从血量作为突破口的。 但是由于试驾场是很少有发包的,包括战车的攻击等等,所以只能通过正常匹配战斗进行扫描。又由于匹配模式中没…

局域网会议软件

局域网会议软件怎么选?连通宝视频会议系统,当然也可以从以下维度进行视频会议选择。 1、部署简单方便连通宝视频会议系统部署简单,五分钟部署专业级的视频会议系统,系统支持主流视频会议设备,支持桌面型会议、机顶盒型…

字节面试挂在2面,复盘总结了经验,决定再战一次.....

先说下我基本情况,本科不是计算机专业,现在是学通信,然后做图像处理,可能面试官看我不是科班出身没有问太多计算机相关的问题,因为第一次找工作,字节的游戏专场又是最早开始的,就投递了&#xf…

算法修炼之练气篇——练气十一层

博主:命运之光 专栏:算法修炼之练气篇 前言:每天练习五道题,炼气篇大概会练习200道题左右,题目有C语言网上的题,也有洛谷上面的题,题目简单适合新手入门。(代码都是命运之光自己写的…

【2023 阿里云云计算工程师 ACP 认证练习题库】01、VPC 专有网络题库

目录 一、多选题 1 1 答案与解析 2 2 答案与解析 3 ​3 答案与解析 辑 4 4 答案与解析 5 5 答案与解析 6 ​6 答案与解析 7 7 答案与解析 8 ​8 答案与解析 9 ​9 答案与解析 10 ​10 答案与解析 11 ​11 答案与解析 12 ​12 答案与解析 13 ​13…

HTB靶机011-Node-WP

11-Node 10.10.10.58 1、PortScan 上来端口扫描,masscan扫全端口,nmap快速扫前100端口 ┌──(xavier㉿kali)-[~] └─$ sudo masscan 10.10.10.58 -p1-65535 -e tun0 --max-rate 500┌──(xavier㉿kali)-[~] └─$ sudo nmap -sSV -T4 -F 10.10.10.…

需求、测试用例、BUG、软件的生命周期开发模型(瀑布、螺旋、增量迭代、敏捷)和测试模型(V模型和W模型)【详细介绍】

本篇文章将详细介绍测试中的相关概念(需求、BUG、测试用例)以及常见的开发模型和测试模型。 目录 一、需求 1.需求的定义 2.需求的产生 3.测试人员眼中的需求 练习:将“删除微信聊天记录功能是否正常”的需求拆分成子需求(测…

Google I/O 2023 - Flutter 3.10 发布

核心部分原文链接:https://medium.com/flutter/whats-new-in-flutter-3-10-b21db2c38c73 Flutter 3.10 主要包括有对 Web、mobile、graphics、安全性等方面的相关改进,核心其实就是: iOS 默认使用了 Impeller 一堆新的 Material 3 控件袭来…

Redis(9)分布式锁(2)

主从复制主节点宕机导致锁失效问题 主节点会不断的把自己的数据传递给从节点,来保证主节点的数据和从节点的数据是相等的, 毕竟不是在同一台机器,主和从之间会存在一定的延时,主从同步也会存在一定的延时 1)现在有一个线程1来进行…

人工智能引发了科学研究的革命

人工智能引发了科学研究的革命 科学研究从第一,第二范式,升级到第三范式 趣讲大白话:人工智能成精了 【趣讲信息科技162期】 **************************** 国内顶尖的AI专家陆奇总结 科学研究的五个范式 1、经验主义(比如中医&am…

Windows10安装二进制Mysql-5.7.41

1.创建my.ini [mysqld] ##skip-grant-tables1 port 3306 basedirD:/webStudy/mysql-5.7.41 datadirE:/adata/mysqlData max_connections200 character-set-serverutf8 default-storage-engineINNODB sql_modeNO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES [mysql] default-char…

软件测试面试题【2023最新合集】

收集了各大公司的面试经验,现整理出来,希望能给正在找工作的志同道合的小伙伴一些指引,本文会持续更新的哦。 1、 CPU 和 GPU的区别 一个是通用计算,一个是专用计算。 CPU主要负责操作系统和应用程序,GPU主要负责…

LDAP配置与安装

LDAP配置与安装 一、安装LDAP1、安装OpenLDAP及相关依赖包2、查看OpenLDAP版本3、配置OpenLDAP数据库4、设置OpenLDAP的管理员密码5、修改配置文件5.1. 修改{2}hdb.ldif文件5.2. 修改{1}monitor.ldif文件5.3. 修改{-1}frontend.ldif文件 6、验证LDAP的基本配置7、修改LDAP文件权…

python-39-异步aiohttp爬取数据

Python分别用单线程,多线程,异步协程爬取一部小说,最快仅需要5s Python异步爬虫之协程抓取妹子图片(aiohttp、aiofiles) Python爬虫——教你异步爬虫二十秒爬完两百多万字六百多章的小说 python爬虫-异步爬虫 用python批量把小说编号由大写数…

RVO的寻路障碍物改进

先说下原理&#xff1a;RVO的障碍识别是通过链接的坐标点数组围成的区域&#xff0c;收尾相接形成的。 namespace RVO { /** * <summary>Defines static obstacles in the simulation.</summary> * 障碍区的点坐标数据结构&#xff0c;是个双向链表结构 *通过Sim…