JUC基础-0601
6 多线程锁
6.1 锁的八个问题演示
class Phone {public static synchronized void sendSMS() throws Exception {//停留4秒TimeUnit.SECONDS.sleep(4);System.out.println("------sendSMS");}public synchronized void sendEmail() throws Exception {System.out.println("------sendEmail");}public void getHello() {System.out.println("------getHello");}
}
-
标准访问,先打印短信还是邮件
- ------sendSMS
- ------sendEmail
-
停 4 秒在短信方法内,先打印短信还是邮件
- ------sendSMS
- ------sendEmail
-
新增普通的 hello 方法,是先打短信还是 hello
- ------getHello
- ------sendSMS
-
现在有两部手机,先打印短信还是邮件
- ------sendEmail
- ------sendSMS
-
两个静态同步方法,1 部手机,先打印短信还是邮件
- ------sendSMS
- ------sendEmail
-
两个静态同步方法,2 部手机,先打印短信还是邮件
- ------sendSMS
- ------sendEmail
-
1 个静态同步方法,1 个普通同步方法,1 部手机,先打印短信还是邮件
- ------sendEmail
- ------sendSMS
-
1 个静态同步方法,1 个普通同步方法,2 部手机,先打印短信还是邮件
- ------sendEmail
- ------sendSMS
分析:两点:
- 是否用的同一把锁
- 锁的范围是怎样的?
6.2 总结
- 两个线程的创建之间间隔了100ms,则短信线程先创建,邮件后创建
- sleep不会释放锁,两个线程一起等待4秒后,顺序和1一样
- hello不同步的,SMS等待4秒,所以先Hello
- 两部手机,两个同步监视器,互相不干扰,SMS睡4秒,所以先email
- 两个静态方法,锁是静态类的Class,所以顺序和1一样,因为同一把锁
- 两个静态方法,两部手机,但是锁还是一个,和5一样
- 一个锁是Class,一个锁是this,互相不影响,所以email快,SMS睡4秒所以慢
- 两把锁,几个手机都一样,锁不同,顺序和7一样。
具体表现为以下 3 种形式。
对于普通同步方法,锁是当前实例对象。
对于静态同步方法,锁是当前类的 Class 对象。
对于同步方法块,锁是 Synchonized 括号里配置的对象
6.3 公平锁和非公平锁
例如:ReentrantLock的无参构造,就是一个非公平锁,会出现一个线程消耗所有资源,其他线程饿死的问题。
// 非公平锁演示
private Lock lock = new ReentrantLock();
// 或这样也是非公平锁
private Lock lock = new ReentrantLock(false);// 公平锁
private Lock lock = new ReentrantLock(true);
公平锁与非公平锁优缺点:
- 非公平锁:
- 效率高
- 线程饿死
- 公平锁:
- 阳光普照
- 效率相对低
- 想要效率高:选非公平锁
- 想要公平:公平锁
公平锁与非公平锁源码实现:
- 非公平锁:占据锁之后之间进行后续操作
static final class NonfairSync extends Sync {private static final long serialVersionUID = 7316153563782823691L;/*** Performs lock. Try immediate barge, backing up to normal* acquire on failure.*/final void lock() {if (compareAndSetState(0, 1))setExclusiveOwnerThread(Thread.currentThread());elseacquire(1);}protected final boolean tryAcquire(int acquires) {return nonfairTryAcquire(acquires);}
}
- 公平锁:里面有一个acquires 参数,并且判断时先执行hasQueuedPredecessors()方法,相当于先礼貌的问一句,这里有人吗;没人就继续操作,有人就会排队。
static final class FairSync extends Sync {private static final long serialVersionUID = -3000897897090466540L;final void lock() {acquire(1);}/*** Fair version of tryAcquire. Don't grant access unless* recursive call or no waiters or is first.*/protected final boolean tryAcquire(int acquires) {final Thread current = Thread.currentThread();int c = getState();if (c == 0) {if (!hasQueuedPredecessors() &&compareAndSetState(0, acquires)) {setExclusiveOwnerThread(current);return true;}}else if (current == getExclusiveOwnerThread()) {int nextc = c + acquires;if (nextc < 0)throw new Error("Maximum lock count exceeded");setState(nextc);return true;}return false;}
}public final boolean hasQueuedPredecessors() {// The correctness of this depends on head being initialized// before tail and on head.next being accurate if the current// thread is first in queue.Node t = tail; // Read fields in reverse initialization orderNode h = head;Node s;return h != t && ((s = h.next) == null || s.thread != Thread.currentThread());
}
6.4 可重入锁(递归锁)
synchronized(隐式)和Lock(显示)都是可重入锁
synchronized的加锁和释放都是自动的,所以是隐式的;Lock是显式的。
简单讲:如果一个线程拿到了锁,那么所有需要这个锁的地方,他都可以进入了
可重入锁,又称为递归锁,是一种递归无阻塞的同步机制。"可重入"的意思是如果一个线程已经持有了一个锁,那么这个线程可以再次获取同一把锁而不会被锁阻塞。这个特性可以在递归或者需要多次访问同步资源的场合简化编程。
在Java中,synchronized和ReentrantLock都是可重入锁。比如:
public class Example {public synchronized void method1() {method2();}public synchronized void method2() {// do something}
}
在这个例子中,一个线程进入method1
方法后,得到了对象锁,然后它可以再次进入method2
方法而不会阻塞,因为它已经持有了对象锁。
同样的,使用ReentrantLock也能达到类似的效果:
import java.util.concurrent.locks.ReentrantLock;public class Example {private final ReentrantLock lock = new ReentrantLock();public void method1() {lock.lock();try {method2();} finally {lock.unlock();}}public void method2() {lock.lock();try {// do something} finally {lock.unlock();}}
}
在这个例子中,线程进入method1
方法后,获取了锁,然后它可以进入method2
方法并再次获取锁,而不会被阻塞。需要注意的是,每次调用lock()
方法,引用计数就加1,每次调用unlock()
方法,引用计数就减1。只有当引用计数为0时,锁才真正被释放。
这种锁的好处是,同一个线程可以多次获取同一把锁,避免了死锁。缺点是可能导致锁保持得过久,从而影响系统性能。
LocK可重入锁演示:
//Lock演示可重入锁Lock lock = new ReentrantLock();//创建线程new Thread(()->{try {//上锁lock.lock();System.out.println(Thread.currentThread().getName()+" 外层");try {//上锁lock.lock();System.out.println(Thread.currentThread().getName()+" 内层");}finally {//释放锁lock.unlock();}}finally {//释放做lock.unlock();}},"t1").start();
在这段代码里面,如果不释放锁,后面的会获取不到锁。
6.5 死锁
- 定义:两个或者两个以上进程在执行过程中,因为争夺资源而造成一种互相等待的现象,如果没有外力干涉,他们无法再执行下去
- 产生死锁原因:
- 系统资源不足
- 进程运行推进顺序不合适
- 资源分配不当
- 验证死锁命令
- jps:ps -ef
- jstack :jvm自带堆栈工具
相关文章:
JUC基础-0601
6 多线程锁 6.1 锁的八个问题演示 class Phone {public static synchronized void sendSMS() throws Exception {//停留4秒TimeUnit.SECONDS.sleep(4);System.out.println("------sendSMS");}public synchronized void sendEmail() throws Exception {System.out.p…...
bash特性
bash bash是一个命令处理器,运行在文本窗口zh哦那个,执行用户输入的命令。 1、bash特性–历史命令 保留用户的历史执行的命令,可以使用history查看之前执行过的命令 #通过$HISTORY查看保存的命令条数 echo $HISTORY #存放用户执行的历史…...

[Flink] Flink On Yarn(yarn-session.sh)启动错误
在Flink上启动 yarn-session.sh时出现 The number of requested virtual cores for application master 1 exceeds the maximum number of virtual cores 0 available in the Yarn Cluster.错误。 版本说明: Hadoop: 3.3.4 Flink:1.17.1 问题…...
玩转css逐帧动画,努力成为更优质的Ikun~
🎉 一、前言 css3的animation想必大家都知道吧,那 steps 逐帧动画你知道吗?对于我来说,实际工作及练习中也很少用到这种跳跃式变化的动画,而它start和end的解释又比较“不说人话”,以前用到steps动画的时候…...
Linux Capabilities
Linux Capabilities是一种细粒度的权限管理机制,用于将root用户的特权划分为具体的功能集。它允许将部分root特权授予非root进程。 可以在shell中运行: man capabilities将显示capability man page,其中包含有关Linux功能的详细信息。 文章目录 什么是CapabilitiesLinux Cap …...

【自制C++深度学习框架】前言
KuiperCourse 介绍 此GitHub项目是一个初学者的深度学习框架,使用C编写,旨在为用户提供一种简单、易于理解的深度学习实现方式。以下是本项目的主要特点和功能: 计算图:使用计算图来描述深度学习模型的计算过程,利用计…...

【高危】泛微 e-cology9 存在任意用户登录漏洞
漏洞描述 泛微协同管理应用平台(e-cology)是一套企业大型协同管理平台。 泛微e-cology9部分版本中存在前台任意用户登录漏洞,由于系统默认配置固定密钥进行用户身份验证。 当存在/mobile/plugin/1/ofsLogin.jsp文件时(可能通过插件方式安装࿰…...
1TB文本的实时全文检索系统搭建
1个T的文本是多大呢?1TB 1000GB,1GB是10亿,1TB就是1万亿字节。如果是英文字符,1TB文本就是1万亿个英文字符,如果是中文字符而且都是UTF8格式,1个中文字符占3个字节,1TB文本是3333亿中文字符&am…...
RHCA---DO477---变量实验
实验目的如下: 1. 环境准备: 使用命令lab inventory-variables start初始化环境 2. 进入/home/student/git-repos目录克隆下载http://git.lab.example.com:8081/git/inventory-variables.git 3. 将目录下yaml文件内容以group_vars形式修改 4. 部署并将修改后ansible-playbook代…...

毕业生高频常用材料线上签,高校毕业季契约锁电子签章一站式助力
据人社部消息,2023年全国高校毕业生总规模将达1158万人!毕业季开启,全国各地高校普遍面临三方协议、成绩单、证书、证明等毕业生高频常用材料签署量激增的现状。学生、教职工、学校常常疲于应对机械化的材料盖章工作。 #毕业季高频常用材料清…...

.ini配置文件介绍与解析库使用
【前言】 ini 文件是英文"Initialization"的缩写,即初始化文件。它用来配置特定应用软件以实现对程序初始化或进行参数设置。.ini文件由节(section)、键(key)、值(value)三种模块构成。在windows系统/嵌入式软件中有很多XXX.ini文件,例如Syste…...
牛客网Linux错题七
1.如何在命令行查看一台linux机器的CPU、SWAP分区信息、硬盘信息?(ACD) A. cat /proc/cpuinfo B. du C. cat /proc/swaps D. df -Ih 解: cat /proc/cpuinfo查看Linux设备的CPU信息,cat /proc/swaps查看Linux设备的交换分区信息…...
牛课刷题Day5(编程题)
1.合并数组 arr1 和数组 arr2。不要直接修改数组 arr,结果返回新的数组 正确答案: function concat(arr1, arr2) {let carr1.concat(arr2)return c } 解析: js的Array对象提供了一个叫concat()方法,连接两个或更多的数组&#x…...

javascript基础二十五:说说你对函数式编程的理解?优缺点?
一、是什么 函数式编程是一种"编程范式"(programming paradigm),一种编写程序的方法论 主要的编程范式有三种:命令式编程,声明式编程和函数式编程 相比命令式编程,函数式编程更加强调程序执行…...
常见JavaScript加密算法、JS加密算法
常见JavaScript加密算法、JS加密算法 一、SHA-256加密算法二、Base64编码算法三、RSA加密算法四、AES加密算法五、HMAC-SHA256算法六、PKCS7填充 一、SHA-256加密算法 SHA-256是一种密码散列函数,可以将任意长度的消息压缩成256位的摘要值。以下是使用JavaScript实现…...
题解2023.6.5
D - Factorial Divisibility 对于a[i]>x的数一定可以整除,考虑a[i]<x的数,因为(x1)*x! (x1)! 统计ai出现的次数, 把他转换为大的阶乘, 如果, 最终1到x - 1, ai的出现次数均为0则说明可以被x!整除 #pragma GCC optimize(2) #pragma GCC optimiz…...

与声音计算研究相关的挑战赛——DCASE和L3DAS
前言:在本专栏的系列博文中,我将包含声学场景识别、声音事件检测、声源位置估计等利用机器学习或深度学习技术进行研究的、基于声音信号的相关工作成为“声音计算”。 本篇博文主要介绍与声音计算相关的两个近些年持续跟进的挑战赛:DCASE和L…...

实训总结-----Scrapy爬虫
1.安装指令 pip install scrapy 2.创建 scrapy 项目 任意终端 进入到目录(用于存储我们的项目) scrapy startproject 项目名 会在目录下面 创建一个以 项目名 命名的文件夹 终端也会有提示 cd 项目名 scrapy genspider example example.com 3.运行爬虫指令 scrapy craw…...
前端开发职业规划指南:如何做好职业规划与发展
引言 前端开发是目前互联网行业中最火热的职业之一,也是非常具有发展前景的职业之一。随着互联网技术的不断更新和发展,前端开发的职业规划也在不断地发生变化。本文将从几个方面来探讨前端开发的职业规划。 一、职业发展路径 1.前端初级工程师 前端初…...

创业第一步:如何写好商业计划书
即使你的项目不需要融资,你也把标准商业计划书作为一个工具模板来应用,帮助更全面的盘点你要做的事情。 撰写一份性感的商业计划书如同造房子:第一步是科学设计,打好结构(有清晰的撰写逻辑);第…...

手游刚开服就被攻击怎么办?如何防御DDoS?
开服初期是手游最脆弱的阶段,极易成为DDoS攻击的目标。一旦遭遇攻击,可能导致服务器瘫痪、玩家流失,甚至造成巨大经济损失。本文为开发者提供一套简洁有效的应急与防御方案,帮助快速应对并构建长期防护体系。 一、遭遇攻击的紧急应…...

3.3.1_1 检错编码(奇偶校验码)
从这节课开始,我们会探讨数据链路层的差错控制功能,差错控制功能的主要目标是要发现并且解决一个帧内部的位错误,我们需要使用特殊的编码技术去发现帧内部的位错误,当我们发现位错误之后,通常来说有两种解决方案。第一…...

基于Flask实现的医疗保险欺诈识别监测模型
基于Flask实现的医疗保险欺诈识别监测模型 项目截图 项目简介 社会医疗保险是国家通过立法形式强制实施,由雇主和个人按一定比例缴纳保险费,建立社会医疗保险基金,支付雇员医疗费用的一种医疗保险制度, 它是促进社会文明和进步的…...
五年级数学知识边界总结思考-下册
目录 一、背景二、过程1.观察物体小学五年级下册“观察物体”知识点详解:由来、作用与意义**一、知识点核心内容****二、知识点的由来:从生活实践到数学抽象****三、知识的作用:解决实际问题的工具****四、学习的意义:培养核心素养…...
postgresql|数据库|只读用户的创建和删除(备忘)
CREATE USER read_only WITH PASSWORD 密码 -- 连接到xxx数据库 \c xxx -- 授予对xxx数据库的只读权限 GRANT CONNECT ON DATABASE xxx TO read_only; GRANT USAGE ON SCHEMA public TO read_only; GRANT SELECT ON ALL TABLES IN SCHEMA public TO read_only; GRANT EXECUTE O…...
linux 错误码总结
1,错误码的概念与作用 在Linux系统中,错误码是系统调用或库函数在执行失败时返回的特定数值,用于指示具体的错误类型。这些错误码通过全局变量errno来存储和传递,errno由操作系统维护,保存最近一次发生的错误信息。值得注意的是,errno的值在每次系统调用或函数调用失败时…...

论文浅尝 | 基于判别指令微调生成式大语言模型的知识图谱补全方法(ISWC2024)
笔记整理:刘治强,浙江大学硕士生,研究方向为知识图谱表示学习,大语言模型 论文链接:http://arxiv.org/abs/2407.16127 发表会议:ISWC 2024 1. 动机 传统的知识图谱补全(KGC)模型通过…...

令牌桶 滑动窗口->限流 分布式信号量->限并发的原理 lua脚本分析介绍
文章目录 前言限流限制并发的实际理解限流令牌桶代码实现结果分析令牌桶lua的模拟实现原理总结: 滑动窗口代码实现结果分析lua脚本原理解析 限并发分布式信号量代码实现结果分析lua脚本实现原理 双注解去实现限流 并发结果分析: 实际业务去理解体会统一注…...

IoT/HCIP实验-3/LiteOS操作系统内核实验(任务、内存、信号量、CMSIS..)
文章目录 概述HelloWorld 工程C/C配置编译器主配置Makefile脚本烧录器主配置运行结果程序调用栈 任务管理实验实验结果osal 系统适配层osal_task_create 其他实验实验源码内存管理实验互斥锁实验信号量实验 CMISIS接口实验还是得JlINKCMSIS 简介LiteOS->CMSIS任务间消息交互…...

算法笔记2
1.字符串拼接最好用StringBuilder,不用String 2.创建List<>类型的数组并创建内存 List arr[] new ArrayList[26]; Arrays.setAll(arr, i -> new ArrayList<>()); 3.去掉首尾空格...