复习之 java 锁

裁员在家,没有面试机会,整理整理面试知识点吧!

不得不知道的java 锁

Java 中,提供了两种方式来实现同步互斥访问(也就是锁):synchronized 和 Lock

多线程编程中,有可能会出现多个线程同时访问同一个共享、可变资源的情况,这个资源我们称之其为临界资源;

这种资源可能是: 对象、变量、文件等。
共享:资源可以由多个线程同时访问
可变:资源可以在其生命周期内被修改
当多个线程执行一个方法时,该方法内部的局部变量并不是临界资源,因为这些局部变量是在每个线程的 ,私有栈中,因此不具有共享性,不会导致线程安全问题。
synchronized
jvm 内置的锁,可以对临界资源同步访问,是可重入的。
实例方法加锁:锁的是当前对象。同一个线程

静态方法加锁:锁的是当前类对象

静态代码块:锁的是代码块里的对象

synchronized底层原理
synchronized 是基于JVM 的内置锁,底层通过通过内部Monitor(监视器锁)实现,监视器锁的实现依赖底层操作系统的Mutex lock(互斥锁)实现,它是一个重量级锁性能较低。jdk1.5 以后哦哦进行了优化。偏向锁,轻量级锁(自适应自旋锁),重量级锁。使得synchronized 性能跟Lock 差不多。 
synchronized关键字被编译成字节码后会被翻译成 monitorenter monitorexit 两条指令分别在同步块逻辑代码的起始位置
与结束位置。
对象结构
一个对象包括:对象头,对象数据,对其填充
对象头包括:
      markworld :用于存储对象自身运行时数据,比如hashcode,GC分代年龄,锁状态标志,线程持有的锁,线程偏向ID,偏向时间戳等,
      klass : 对象指向它的类元数据指针,虚拟机通过这个指针确定这个对象是哪个类的实例
      数组长度(数组才有)
synchronized 锁升级过程
1 首先一个线程t1请求加锁资源,此时对象头里线程偏向id 存储当前线程的线程id,并且锁的状态标志位加锁。现在是一个偏向锁
2 当再有第二个线程t2过来尝试加锁,发现已经被加锁了,检查加锁的是否是自己,不是t2 则尝试修改对象头偏向id 为自己,修改失败,当t1 运行到安全点时,判断是否t1 已经退出代码块,如果是则t1 释放锁,t2 添加偏向锁,如果t1没有执行完,则升级为轻量级锁
3 轻量级锁,t2 会通过CAS 方式自旋尝试加锁,超过多少次没有获取到锁,则升级成重量级锁,因为自旋获取锁,也是比较费CPU 资源的

锁粗话 StringBubber .append 线程安全,多次append 就会进行一个锁 锁粗话

锁清除 synchronized (new object()) ,因为每次都是锁新对象,jvm 认为没有意思 所以不会加锁 

逃逸分析:如果一个对象只有在一个线程栈中用到,没有其他线程用到,这样这个对象就会在一部分会在栈中不放到堆里。

ReentrantLock 时基于AQS 实现的同步手段,跟synchronized 也是一种互斥锁。保证线程安全。但是它又比synchronized 多了很多特性,比如:公平锁,中断锁,锁超时等等。
ReentrantLock 原理
1 通过cas 方式 设置变量,expect–期望值  update–新值,如果期望值跟内存值相等,修改内存值为新的值。当前线程设置独占访问
 unsafe.compareAndSwapInt(this, stateOffset, expect, update);
setExclusiveOwnerThread(Thread.currentThread()); 

2 如果期望值跟内存之不相等,则获取共享变量判断是否等0 如果等于,则说明没有加锁,通过cas 继续加锁,如果不能与获取设置的线程,跟当前线程比对是否相等,如果相等则说明相同线程加锁,可以继续加锁,重入锁。

3 如果既不能加锁,也不是重入锁。则把当前线程放入队列里

核心思想:就是线程请求一个共享资源,如果共享资源空闲,这对共享资源加锁,如果共享资源已经加锁,则进入阻塞状态以及被唤醒时分配机制。通过CLH队列(虚拟双向队列)实现锁的,既获得不到锁的加入到队列中。

用大白话来说,AQS就是基于CLH队列,用volatile修饰共享变量state,线程通过CAS去改变状态符,成功则获取锁成功,失败则进入等待队列,等待被唤醒。

ReentrantLock lock = new ReentrantLock(false);//false为非公平锁
lock.lock();
lock.tryLock(30, TimeUnit.SECONDS);// 30秒没加上锁,自动释放
lock.lockInterruptibly();// 锁中断

 Condition condition = lock.newCondition();  //lock 等待通知
 condition.await();
 condition.signal();

 可以替换 synchronized  wait notify  

 obj.wait(); obj.notify(); 在synchronized 里否则报错

死锁:a线程锁定一个资源,同时想获取b线程的资源,b线程锁定一个资源,同时想获取a线程的资源。

java 死锁必要条件
1 互斥条件:资源不能被共享,只能由一个线程使用(threadLocal)  
2 请求保持条件:一个线程因请求其他资源而阻塞时,对目前拥有的资源保持不放。(一次性请求所有资源)

3 不可抢占条件:进程已获得的资源,在未使用完之前,不能被剥夺( 超时500毫秒 ,自动释放锁)  lock.tryLock(timeout)。
4 相互等待条件:t1 修改下单状态,减库存,  t2减库存,下单  相互持有对方的锁 等待,死锁(逻辑顺序一致) 

只要打破上面任意一个条件,即不会死锁

什么情况下会释放synchronized

执行完成会释放锁

抛异常会释放锁

wait 释放当前锁

return 释放锁

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

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

相关文章

期权中非常重要的行权!不懂行权先别交易!

今天带你了解期权中非常重要的行权!不懂行权先别交易!期权是金融市场中一种常见的衍生品工具,它给予持有者在特定时间内以特定价格购买或出售某个资产的权利。而“行权”是指期权持有者行使期权权利的行为。 期权行权是指期权持有者选择执行…

超网和无类间路由是什么?

​一、超网概述 超网是将多个连续的网络地址组合成一个增加的网络地址的技术。常用于减少路由器的路由表大小,网络的可扩展性。通过合并连续的子网,超网可以减少路由入侵的数量,从而提高网络的效率。 超网的实现基于合并多个具有连续IP地址…

java知识点详解——异常

当输入的数不是整数时 会报错 当输入的被除数为0时 会报错 在以前我们会使用if—else语句用来堵住漏洞,但是那样相当繁琐,很难穷举所有错误 Scanner in new Scanner(System.in); System.out.print("请输入被除数:"); int num1 in.nextInt(…

【Python快速入门和实践016】Python常用脚本-对视频抽取指定帧数并保存

一、功能介绍 这段代码的功能是从一个视频文件中抽取指定数量的帧,并将这些帧保存为图像文件。步骤如下: 设置路径和参数: video_path:视频文件的路径。image_folder:保存抽取图像的目录。num_frames_to_extract&#…

工业相机图像采集卡

什么是图像采集卡? 图像采集卡又称为图像卡,它将相机的图像视频信号,以帧为单位传送到计算机的内存和VGA帧存,供计算机处理,存储,显示和传输等使用。在机器视觉系统中,图像采集卡采集到的图像供…

【C语言】双链表

🦄个人主页:小米里的大麦-CSDN博客 🎏所属专栏:C语言数据结构_小米里的大麦的博客-CSDN博客 🎁代码托管:黄灿灿/数据结构 (gitee.com) ⚙️操作环境:Visual Studio 2022 目录 一、什么是双链表? 二、双链表温习 1. 双链表的结构…

【Django开发】前后端分离django美多商城项目第2篇:展示用户注册页面,1. 创建用户模块子应用【附代码文档】

全套笔记资料代码移步: 前往gitee仓库查看 感兴趣的小伙伴可以自取哦~ 本教程的知识点为: 项目准备 项目准备 配置 1. 修改settings/dev.py 文件中的路径信息 2. INSTALLED_APPS 3. 数据库 用户部分 图片 1. 后端接口设计: 视图原型 2. 具体…

如何诱导AI犯罪-提示词注入

我们用到的大模型基本把政治类信息、犯罪相关信息都已屏蔽。但是,黑客依旧可以使用提示词诱导和提示词注入的方式对大模型进行攻击。 1、提示词诱导 如果直接让AI提供犯罪过程,AI会直接拒绝。虽然AI对于大部分知识了然于心,但因为经过了人工…

javase综合案例3 -- 通讯录

文章目录 一,项目要求基础功能拓展 二,导入jar包 pinyin4j.jar三,程序报下建立Pinyin4j类四,创建实体类Contact五,创建通讯录接口ContactDao六,创建ContactDao接口的视线子类ContactDaoImpl6.1 创建全局的M…

【Dash】Dash模块介绍

什么是Dash? Dash 是一个开源的 Python 框架,用于创建基于 Web 的应用程序。它由 Plotly 公司开发,专为数据科学家和分析师设计,以便他们可以构建自定义的数据可视化 Web 应用程序,而无需具备前端开发知识。Dash 提供…

NGINX项目实战

一、nginx四层代理 部署支持4层TCP/UDP代理的Nginx服务器 部署nginx服务器 编译安装必须要使用--with-stream参数开启4层代理模块。 [rootproxy ~]# rm -rf /usr/local/nginx/ #清理环境 [rootproxy nginx-1.16.1]# ./configure --with-http_ssl_module --with-stream #开…

Oracle特有的DECODE函数

Oracle中的DECODE函数是一种条件表达式函数,用于基于给定的条件从一组值中选择一个值返回。它的基本语法如下: DECODE(expression, search1, result1, [search2, result2, ...], [default])expression:要比较的表达式或列。searchN&#xff…

DDPM 核心代码解析(1)

所有代码 已上传至GitHub - duhanyue349/diffusion_model_learned_ddpm_main: 扩散模型基础框架源代码 目录结构如下 在train_cifar.py 中展示了扩散模型训练的所有代码 如果没有安装wandb 可以在create_argparser()设置 log_to_wandbFalse 一、加载模型参数 args 这里用了一…

直播圈不再只讲技术和千川,管理成为新焦点

直播圈不讲技术,也不讲千川啦,开始讲管理啦,感叹直播带货发展真快,都说要傻瓜化,讲的东西一年能迭代 3 个版本,甚至带货线下课不讲半天团队管理你的课都显得low。关键没一个能告诉你管理是什么管什么&#…

【1】CPU飙升到200%以上问题汇总

原链接 【1】CPU飙升到200%以上问题汇总 CPU飙升到200%以上是生成中常见的问题 注意: 1. linux的cpu使用频率是根据cpu个数和核数决定的 2. top,然后你按一下键盘的1,这就是单个核心的负载,不然是所有核心的负载相加,…

弹幕背后:B站UP主创作服务解析

引言 在B站,每一条飘过的弹幕都是一个故事的碎片,它们汇聚成一幅幅生动的社交画卷。这里,不仅仅是一个视频分享平台,弹幕背后更是一个充满活力的创作者生态系统。B站以其独特的弹幕文化,为创作者和观众之间搭建起了一座…

RxJava基础使用

Rx思想 事件从起点流向终点。 过程中可以对事件进行拦截,拦截时可以对事件进行处理,处理后将处理后的事件继续流向终点。 终点接收上一次处理后的事件。 获取网络图片并显示 基础实现 使用Observable.just(path) 创建图片路径的Observable。 使用m…

Unity | Shader基础知识(第二十集:应用-简易流光、LOD)

目录 一、前言 二、LOD 1.什么是LOD 2.代码如何调节LOD 三、流光 1.资源准备 2.uv移动 3.获取图片中的uv 4.改变uv去取流光的颜色(时间的应用) 5.图片叠加 6.透明图片的叠加 四、纯净代码 五、作者的碎碎念 一、前言 有小伙伴问&#xf…

Studying-代码随想录训练营day45| 115.不同的子序列、583. 两个字符串的删除操作、72. 编辑距离、编辑距离总结篇

第45天,子序列part03,编辑距离💪(ง •_•)ง,编程语言:C 目录 115.不同的子序列 583. 两个字符串的删除操作 72. 编辑距离 编辑距离总结篇 115.不同的子序列 文档讲解:代码随想录不同的子序列 视频讲…

分布式搜索引擎ES--Elasticsearch集群

1.Elasticsearch集群的概念 分片机制:每个索引都可以被分片 索引my_doc只有一个主分片;索引shop有三个主分片;索引shop2有5个主分片;(参考前面案例) 每个主分片都包含索引的数据,由于目前是单机,所以副分片是没有的&a…