常见的锁策略(面试八股文)
1.乐观锁vs悲观锁
乐观锁:预测该场景中不太会出现锁冲突的情况。(后续做的工作会更少)
悲观锁:预测该场景非常容易出现锁冲突(后续做的工作会更多)
锁冲突:多个线程同时尝试去获得同一把锁,其中一个线程能够获取成功,其余线程阻塞等待
乐观锁和悲观锁是在加锁之前,对锁冲突概率的预测,决定开销的多少
2.重量级锁vs轻量级锁
重量级锁:加锁的开销是比较大的(花的时间多,占用的资源多),一个悲观锁很可能就是一个重量级锁(不绝对)
轻量级锁:加锁的开销比较小(花的时间少,占用的资源少),一个乐观锁很可能就是一个轻量级锁(不绝对)
.重量级和轻量级锁是在加锁之后对锁实践开销的考量
3.读写锁vs互斥锁
互斥锁:就是普通的锁,没有为读操作和写操作分开加锁,synchronized就是互斥锁
读写锁:把读操作加锁和写操作加锁分开了
因为多线程同时去读同一个变量不会涉及到线程安全问题
如果两个线程,一个线程读加锁,另一个线程也是读加锁,不会发生锁竞争(多线程并发执行的效率就会更高)
如果两个线程,一个线程写加锁,另一个线程也是写加锁,会发生锁竞争
如果两个线程,一个线程写加锁,另一个线程是读加锁,会发生锁竞争
在实践开发中,读操作的频率往往比写操作的频率高,所以通过读写锁可以大大提高程序运行的效率(因为在多个线程对同一个变量进行读取操作的时候不会发生锁竞争,是并发执行的)
4.自旋锁vs挂起等待锁
自旋锁:一种典型的轻量级锁的实现方式,线程在抢锁失败后会进入阻塞状态,要等到获得锁的线程释放锁才能去尝试获取锁,而自旋锁会在获取锁失败了以后,立即再尝试去获取锁,无限循环(一直不停的去尝试获取锁)这样一旦锁被其他线程释放,就能够第一时间获得锁。
优点:一旦锁被释放可以第一时间获得锁(对比挂起等待锁,获得锁的速度会快很多)
缺点:如果锁被其他线程持有的时间比较久,那么就会持续的消耗cpu资源(而挂起等待的时间是不消耗cpu的)
挂起等待锁:是重量级锁的一种典型表现,当出现锁冲突的时候,会牵扯到内核对于线程的调度,使冲突的线程出现挂起(阻塞等待)
5.公平锁vs非公平锁
假设三个线程A, B,C.A先尝试获取锁,获取成功.然后B再尝试获取锁,获取失败,阻塞等待;然后C也尝试获取锁,C也获取失败,也阻塞等待.
当线程A释放锁的时候,会发生啥呢?
公平锁:遵守"先来后到".B比C先来的.当A释放锁的之后,B就能先于C获取到锁
非公平锁:不遵守"先来后到".B和C都有可能获取到锁.
6.可重入锁和不可重入锁
有一个线程,针对同一个对象,连续加锁了两次,如果产生了死锁就是不可重入锁,如果没有产生死锁就是可重入锁
例子:
public synchronized void increase(){synchronized(this){count++;}
}
如上述代码,调用increase方法后会在同一个线程中对同一个对象进行两次加锁,如果是不可重入锁的话,在调用increase方法对类对象进行加锁了以后,执行increase方法中的程序再对类对象进行加锁就会发生阻塞等待,一直要阻塞到第一个对类对象加锁的线程释放锁,但要执行完该线程又需要获得锁了以后才能向下执行,所以程序就卡在了第二次对类对象加锁这里,也就形成了死锁。
死锁的三种经典情况
1.一个线程一把锁,但是是不可重入锁,该线程针对这个锁连续加锁两次,就会出现死锁
2.两个线程,两把锁,这两把线程先分别获取到一把锁,然后再同时尝试获取对方的那把锁
通过下面的代码可以直观的看到该情况
ublic class Demo1 {public static void main(String[] args) {Object blocer1=new Object();Object blocer2=new Object();Thread t1=new Thread(()->{synchronized(blocer1){try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}synchronized(blocer2){System.out.println("t1线程获取两把锁");}}});Thread t2=new Thread(()->{synchronized(blocer2){try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}synchronized(blocer1){System.out.println("t2线程获取两把锁");}}});t1.start();t2.start();}
}
3.N个线程M把锁,N个线程中每个线程都会对多把锁进行加锁,而且加的锁是有重复的,这样在莫种特殊情况下就会形成死锁
产生死锁的四个必要条件
1.互斥使用,一个线程获取到一把锁了以后,其他线程就不能去获取这把锁(实际使用的锁,一般都是互斥的,锁的基本特征)
2.不可抢占,锁只能是持有者主动释放,而不是被其他其他线程直接抢走(也是锁的基本特征)
3.请求和保持,当一个线程去尝试获取多把锁,在获取第二把锁的时候会保持对第一把锁的获取状态(取决于代码结构)
4.循环等待,t1尝试获取locker2,需要t2执行完,释放locker2,t2尝试获取locker1,需要t1执行完,释放locker1,发生了死循环(取决于代码结构)
解决死锁的有效方法
解决死锁主要是针对循环等待这方面来进行解决
当每个线程要获取多把锁,先针对锁进行编号,约定,每个线程如果要获取多把锁,必须先获取编号小的锁,后获取编号大的锁。
只要所有线程加锁的顺序,都严格遵守上述顺序,就一定不会出现循环等待,就解决了死锁
synchronized采用的锁策略
1.即是悲观锁也是乐观锁,即是重量级锁也是轻量级锁,是自适应的
2.重量级锁部分是根据系统的互斥锁实现的,轻量级锁部分是根据自旋锁实现的
3.非公平锁(不会遵循先来后到,锁释放后,那个线程获得锁,各凭本事)
4.可重入锁,同一个线程可以多次获取同一把锁(内部会记录哪个线程拿了锁,记录引用计数,要是是同一个线程拿锁,计数器就加一,此时该线程要解锁的话,计数器就减一,直到1计数器为0才真正解锁)
5.不是读写锁,是普通的互斥锁
synchronized的自适应过程
代码写了一个synchronized之后,这里可能会产生一系列的自适应过程:无锁->偏向锁->轻量级锁->重量级锁
一开始是无锁的,加了synchronized后就对程序加了偏向锁,偏向锁,不是真的加锁,而只是做了一个标记,如果有别的线程来竞争锁了,才会真的加锁,如果没有别的线程竞争,就自始至终都不会真的加锁
偏向锁真的加锁以后就是轻量级锁,但是后续如果竞争这把锁的线程越来越多了(锁冲突更激烈了),从轻量级锁升级成了重量级锁
相关文章:
常见的锁策略(面试八股文)
1.乐观锁vs悲观锁 乐观锁:预测该场景中不太会出现锁冲突的情况。(后续做的工作会更少) 悲观锁:预测该场景非常容易出现锁冲突(后续做的工作会更多) 锁冲突:多个线程同时尝试去获得同一把锁&…...
SO_KEEPALIVE、TCP_KEEPIDLE、TCP_KEEPINTVL、保活包
SO_KEEPALIVE SO_KEEPALIVE 是一个套接字选项,用于设置是否启用 keepalive 机制。在这段代码中没有涉及到 SO_KEEPALIVE 选项的设置。 当 SO_KEEPALIVE 被设置为非零值时,表示启用 keepalive 机制。keepalive 是一种用于检测连接是否仍然有效的机制。通…...

【phaser微信抖音小游戏开发005】画布上添加图片
特别注意:真机模拟的时候,尽量使用网络图片资源,不要在小程序源文件里面使用图片,会出现真机加载不成功,小程序包体积过大的问题。我们学习过程中,只是作为演示使用。 推荐使用场景: 背景图片…...

【设计模式——学习笔记】23种设计模式——外观模式Facade(原理讲解+应用场景介绍+案例介绍+Java代码实现)
文章目录 案例引入介绍基本介绍类图出场角色 案例实现案例一类图代码实现 案例二类图代码实现 外观模式在Mybatis源码中的应用总结文章说明 案例引入 在家庭影院中,要享受一场电影,需要如下步骤: 直接用遥控器:统筹各设备开关开…...
消息队列 -提供上层服务接口
目录 前言封装数据库封装内存操作内存的设计思想 应答模式 代码实现测试代码 前言 我们之前已经将 数据库 的操作 和文件的操作 都完成了, 但是对于上层调用来说, 并不关心是于数据库中存储数据还是往文件中存储数据, 因此 我们提供一个类, 封装一下 上述俩个类中的操作, 并将…...

maven引入本地jar包的简单方式【IDEA】【SpringBoot】
前言 想必点进来看这篇文章的各位,都是已经习惯了Maven从中央仓库或者阿里仓库直接拉取jar包进行使用。我也是🤡🤡。 前两天遇到一个工作场景,对接三方平台,结果对方就是提供的一个jar包下载链接,可给我整…...

【爬虫逆向案例】某易云音乐(评论)js逆向—— params、encSecKey解密
声明:本文只作学习研究,禁止用于非法用途,否则后果自负,如有侵权,请告知删除,谢谢! 【爬虫逆向案例】某易云音乐(评论)js逆向—— params、encSecKey解密 1、前言2、行动…...

【uni-app】【Android studio】手把手教你运行uniapp项目到Android App
运行到Android App基座 选择运行到Android App基座 选择运行项目 1、连接手机,在手机上选择 传输文件。 2、打开 设置-> 关于本机 -> 版本信息->连续点击4-5次版本号 ,输入手机密码,系统就进入了开发者模式。 3、设置 > 其他设…...

多线程(JavaEE初阶系列6)
目录 前言: 1.什么是线程池 2.标准库中的线程池 3.实现线程池 结束语: 前言: 在上一节中小编带着大家了解了一下Java标准库中的定时器的使用方式并给大家实现了一下,那么这节中小编将分享一下多线程中的线程池。给大家讲解一…...

shell清理redis模糊匹配的多个key
#!/bin/bash# 定义Redis服务器地址和端口 REDIS_HOST"localhost" REDIS_PORT6380# 获取匹配键的数量 function get_matching_keys() {local key_pattern"$1"redis-cli -h $REDIS_HOST -p $REDIS_PORT -n 0 KEYS "$key_pattern" }# 删除匹配的键 …...

【电网异物检测硕士论文摘抄记录】电力巡检图像中基于深度学习的异物检测方法研究
根据国家电力行业发展报告统计,截止到 2018 年,全国电网 35 千伏及以上的输电线路回路长度达到 189 万千米,220 千伏及以上输电线路回路长度达73 万千米。截止到 2015年,根据国家电网公司的统计 330 千伏及以上输电线路故障跳闸总…...

C++共享数据的保护
虽然数据隐藏保护了数据的安全性,但各种形式的数据共享却又不同程度地破坏了数据的安全。因此,对于既需要共享有需要防止改变的数据应该声明为常量。因为常量在程序运行期间不可改变,所以可以有效保护数据。 1.常对象 常对象:它…...
MyBatisPlus学习记录
MyBatisPlus(简称MP)是基于MyBatis框架基础上开发的增强型工具,旨在简化开发、提高效率 MyBatisPlus简介 入门案例 创建新模块,选择Spring初始化,并配置模块相关基础信息选择当前模块需要使用的技术集(仅选择MySQL …...

如何开启一个java微服务工程
安装idea IDEA常用配置和插件(包括导入导出) https://blog.csdn.net/qq_38586496/article/details/109382560安装配置maven 导入source创建项目 修改项目编码utf-8 File->Settings->Editor->File Encodings 修改项目的jdk maven import引入…...
libhv之hio_t分析
上一篇文章解析了fd是怎么与io模型关联。其中最主要的角色扮演者:hio_t 1. hio_t与hloop的关系 fd的值即hio_t所在loop ios变量中所在的index值。 hio_t ios[fd] struct hloop_s { ...// ios: with fd as array.index//io_array保存了和hloop关联的所有hio_t&…...

C语言的转义字符
转义字符也叫转移序列,包含如下: 转移序列 \0oo 和 \xhh 是 ASCII 码的特殊表示。 八进制数示例: 代码: #include<stdio.h> int main(void) {char beep\007;printf("%c\n",beep);return 0; }结果: …...

【腾讯云 Cloud Studio 实战训练营】CloudStudio体验真正的现代化开发方式,双手插兜不知道什么叫对手!
CloudStudio体验真正的现代化开发方式,双手插兜不知道什么叫对手! 文章目录 CloudStudio体验真正的现代化开发方式,双手插兜不知道什么叫对手!前言出现的背景一、CloudStudio 是什么?二、CloudStudio 的特点三、CloudS…...

Pandas时序数据分析实践—时序数据集
1. 跑步运动为例,对运动进行时序分析 时序数据是指时间序列数据,是按照时间顺序排列的数据集合,每个数据点都与一个特定的时间戳相关联。在跑步活动中,我们可以将每次跑步的数据记录作为一个时序数据样本,每个样本都包…...
use strict 是什么意思?使用它区别是什么?
use strict 是什么意思?使用它区别是什么? use strict 代表开启严格模式,这种模式下使得 JavaScript 在更严格的条件下运行,实行更严格解析和错误处理。 开启“严格模式”的优点: 消除 JavaScript 语法的一些不合理…...

常见OOM异常分析排查
常见OOM异常分析排查 Java内存溢出Java堆溢出原因解决思路总结 Java内存溢出 java堆用于存储对象实例,如果不断地创建对象,并且保证GC Root到对象之间有可达路径,垃圾回收机制就不会清理这些对象,对象数量达到最大堆的容量限制后就会产生内存溢出异常. Java堆溢出原因 无法在…...

《Qt C++ 与 OpenCV:解锁视频播放程序设计的奥秘》
引言:探索视频播放程序设计之旅 在当今数字化时代,多媒体应用已渗透到我们生活的方方面面,从日常的视频娱乐到专业的视频监控、视频会议系统,视频播放程序作为多媒体应用的核心组成部分,扮演着至关重要的角色。无论是在个人电脑、移动设备还是智能电视等平台上,用户都期望…...
Java - Mysql数据类型对应
Mysql数据类型java数据类型备注整型INT/INTEGERint / java.lang.Integer–BIGINTlong/java.lang.Long–––浮点型FLOATfloat/java.lang.FloatDOUBLEdouble/java.lang.Double–DECIMAL/NUMERICjava.math.BigDecimal字符串型CHARjava.lang.String固定长度字符串VARCHARjava.lang…...
多模态商品数据接口:融合图像、语音与文字的下一代商品详情体验
一、多模态商品数据接口的技术架构 (一)多模态数据融合引擎 跨模态语义对齐 通过Transformer架构实现图像、语音、文字的语义关联。例如,当用户上传一张“蓝色连衣裙”的图片时,接口可自动提取图像中的颜色(RGB值&…...

Mac软件卸载指南,简单易懂!
刚和Adobe分手,它却总在Library里给你写"回忆录"?卸载的Final Cut Pro像电子幽灵般阴魂不散?总是会有残留文件,别慌!这份Mac软件卸载指南,将用最硬核的方式教你"数字分手术"࿰…...
使用Matplotlib创建炫酷的3D散点图:数据可视化的新维度
文章目录 基础实现代码代码解析进阶技巧1. 自定义点的大小和颜色2. 添加图例和样式美化3. 真实数据应用示例实用技巧与注意事项完整示例(带样式)应用场景在数据科学和可视化领域,三维图形能为我们提供更丰富的数据洞察。本文将手把手教你如何使用Python的Matplotlib库创建引…...

使用LangGraph和LangSmith构建多智能体人工智能系统
现在,通过组合几个较小的子智能体来创建一个强大的人工智能智能体正成为一种趋势。但这也带来了一些挑战,比如减少幻觉、管理对话流程、在测试期间留意智能体的工作方式、允许人工介入以及评估其性能。你需要进行大量的反复试验。 在这篇博客〔原作者&a…...

C++ 设计模式 《小明的奶茶加料风波》
👨🎓 模式名称:装饰器模式(Decorator Pattern) 👦 小明最近上线了校园奶茶配送功能,业务火爆,大家都在加料: 有的同学要加波霸 🟤,有的要加椰果…...

从 GreenPlum 到镜舟数据库:杭银消费金融湖仓一体转型实践
作者:吴岐诗,杭银消费金融大数据应用开发工程师 本文整理自杭银消费金融大数据应用开发工程师在StarRocks Summit Asia 2024的分享 引言:融合数据湖与数仓的创新之路 在数字金融时代,数据已成为金融机构的核心竞争力。杭银消费金…...

数据结构:递归的种类(Types of Recursion)
目录 尾递归(Tail Recursion) 什么是 Loop(循环)? 复杂度分析 头递归(Head Recursion) 树形递归(Tree Recursion) 线性递归(Linear Recursion)…...
【Kafka】Kafka从入门到实战:构建高吞吐量分布式消息系统
Kafka从入门到实战:构建高吞吐量分布式消息系统 一、Kafka概述 Apache Kafka是一个分布式流处理平台,最初由LinkedIn开发,后成为Apache顶级项目。它被设计用于高吞吐量、低延迟的消息处理,能够处理来自多个生产者的海量数据,并将这些数据实时传递给消费者。 Kafka核心特…...