【JavaEE】锁的策略

作者主页:paper jie_博客

本文作者:大家好,我是paper jie,感谢你阅读本文,欢迎一建三连哦。

本文于《JavaEE》专栏,本专栏是针对于大学生,编程小白精心打造的。笔者用重金(时间和精力)打造,将MySQL基础知识一网打尽,希望可以帮到读者们哦。

其他专栏:《MySQL》《C语言》《javaSE》《数据结构》等

内容分享:本期将会分享锁的策略知识.这也是面试题常考的问题.

目录

乐观锁与悲观锁

轻量级锁与重量级锁

自旋锁与挂起等待锁

普通互斥锁和读写锁

为什么要引入读写锁

公平锁与非公平锁

可重入锁和不可重入锁

synchronized锁与操作系统自带锁对比

synchronized的优化策略

锁的升级

偏向锁阶段(没有其他锁来竞争)

轻量级锁阶段(有锁竞争,但是不多)

重量级锁阶段(有锁竞争,且很多)

锁消除

锁粗化

相关面试题

你是什么理解乐观锁和悲观锁的,具体怎么实现?

介绍一下读写锁

synchronized是可重入锁吗

什么是自旋锁,为什么要使用自旋锁呢,缺点是什么?


乐观锁与悲观锁

乐观锁就是在加锁前,预估发生锁冲突的概率不大,在进行加锁的时候做的工作不多.这样加锁的速度就会比较快,但是会更容易消耗CPU资源.

悲观锁就是在加锁前,预估发生锁冲突的概率比较大.在进行加锁的时候做的工作就比较多.这样的加锁速度就会比较慢,但这个过程发生问题的几率就不大,还可以更节省CPU资源.

举个栗子:

这就好比两个同学去问问题.A同学认为老师有时间就直接跑过去了,而B同学会先给老师打个电话确认一下老师有没有空再去.A同学就是乐观锁,B同学就是悲观锁. 显而易见,A同学就容易遇到老师很忙的情况,而B同学就可以避免.但老师要是不忙,A同学的速度就会更快.

轻量级锁与重量级锁

轻量级锁就是加锁的开销小,加锁速度快.因为轻量级锁不怎么到涉及线程的调度,所以开销就比较小.

而重量级锁就是加锁的开销比较大,加锁速度慢.因为重量级锁涉及到大量的线程调度,遇到锁竞争就需要将线程调度出CPU,等待解锁再由系统随机唤醒一个等待线程,所所以开销会比较慢.

这里可以理解为轻量级锁就是乐观锁,重量级锁就是悲观锁.而前者是站在结果发生后的角度来评价,后者是站在发生前的角度来预估.

自旋锁与挂起等待锁

自旋锁是轻量级锁的经典实现,自旋锁也就是乐观锁. 它就是在加锁的时候搭配一个while循环,加锁成功就退出循环,要是没有成功发生堵塞,也不会退出CPU,而是通过while循环不断尝试获取到锁. 这种循环就叫做自旋.一旦当其他线程释放锁后,它就可以第一时间拿到锁了. 但是自旋锁只能在锁竞争不大的情况下使用,不然就会白白自旋,浪费CPU资源.

挂起等待锁是重量级锁的经典实现.挂起等待锁也就是悲观锁. 它就是在尝试加锁失败后不会再次尝试获取锁.而是调度出CPU,等待其他线程释放锁后,由系统来随机唤醒一个等待的线程.因为它在等待的过程中会有内核调度器介入,会有大量的线程调度,获取锁的时间就会比较慢.挂起等待锁的适用场景是在锁冲突比较严重的情况下.

而在我们Java中,Synchronized这个锁是一个乐观锁/悲观锁自适应,轻量级锁/重量级锁自适应,自旋/挂起等待锁自适应.它可以根据不同的场景来做切换.

普通互斥锁和读写锁

我们Java的synchronized就是普通互斥锁,不管是读还是写都是进行加锁.而读写锁会有两种情况: 1.加读锁 2. 加写锁. 读写锁就是一个线程读时,另一个线程只能读不能写. 一个线程写时,另一个线程不能读也不能写. 

1 读锁和读锁之间不会发生堵塞.

2 读锁和写锁之间会发生堵塞.

3 写锁和写锁之间会发生堵塞. 

为什么要引入读写锁

因为多线线程进行读操作,它本身就是线程安全的,但是对于普通互斥锁来说,两个线程读,也会发生锁竞争,堵塞,这就会造成一定的性能损失. 但是对读操作不加锁的话,就怕一个线程读,一个线程写,导致读到的内容不完整.

基于这个情况下就引入了读写锁,它就可以解决对于读操作不加锁的问题.直接将读引发的锁竞争的开销给节省下来了,让性能会有很大的提高. 我们在实际开发中读操作是非常多的,使用读写锁对性能就有明显的提升了.

公平锁与非公平锁

公平锁就是遵循先来后到. 假设A锁先进行锁等待,B锁后进行锁等待.等到其他线程将锁释放后,就是A先获取到锁.

非公平锁就是不管你是先进行等待还是后进行等待.等到其他线程释放锁后.大家都可以竞争这把锁.系统的调度是随机的,下一个唤醒谁都不确定.

站在操作系统的角度上来看待锁,就是不公平锁.因为操作系统调度线程是随机的.下一个将谁调度进来,唤醒谁也不确定.我们Java中的synchronized也是不公平锁.而公平锁就需要引入额外的数据结构.

可重入锁和不可重入锁

可重入锁就是对于一个锁对象来说, 同一个线程可以多次获取到这把锁,不会发生死锁.

不可重入锁就是对于一个锁对象来锁,同一个线程不可以多次获取到这个把锁,不然会发生死锁.

我们的synchronized就是可重入锁,它的内部有两个重要的属性, 一个是用来记录当前持有锁的线程.一个是计数器,一次加锁就+1,一次解锁就-1.当变成0就算彻底解锁成功.

synchronized锁与操作系统自带锁对比

synchronized是:

乐观锁/悲观锁自适应

轻量/重量锁自适应

自旋/挂起等待锁自适应

不公平锁

普通互斥锁

系统自带锁是:

悲观锁

重量级锁

挂起等待锁

不公平锁

普通互斥锁

synchronized的优化策略

锁的升级

synchronized内部会有一个升级阶段.当一个线程执行到synchronized这里时,所对象还没被加锁的时候,就会经历: 1.偏向锁阶段 -> 2.轻量级锁阶段 -> 3.重量级锁阶段

偏向锁阶段(没有其他锁来竞争)

就是在这个需要加锁的线程上做一个轻量的标记,并不会真正的去进行加锁.只有等到其他的线程也要对这个锁进行加锁时.它才会在其他线程获取到锁之前将锁获取过来.这样就从偏向锁升级到了轻量级锁.

这里的核心思想就是懒汉模式.不能加锁就不加锁,迫不得已的情况下再进行加锁.这样就可以在没有其他线程需要加锁的情况下省去加锁的开销.

轻量级锁阶段(有锁竞争,但是不多)

这里的轻量级锁实现的就是自旋锁,这里的优点就是可以很快获取到锁,但是会更消耗CPU资源. synchronized内部会记录当前有多少个线程在竞争这把锁,当超过一个量后,轻量级锁就会升级到重量级锁.

重量级锁阶段(有锁竞争,且很多)

这里的重量级锁实现的就是挂起等待锁,遇到锁冲突后就直接挂起等待,也就是调度出CPU,当释放锁后,让系统随机唤醒一个来获取锁.

锁消除

这里也是编译器优化的一种方式.当发现这个代码不需要加锁时,就会将锁消除掉.

锁粗化

锁粗化就是将多个细粒度的锁合并成一个粗粒度的锁. 这里我们可以理解完synchronized{}里的代码越少粒度就越细.大多数情况下是希望粒度越细越容易并发执行代码,但有的情况下还是希望粒度粗一点.

比如:这里的加锁操作太多就会导致锁竞争的开销过大,每次加锁可能都会堵塞.这时将细粒度的锁变成粗粒度的锁就节省了锁堵塞的开销,也会提高效率.

相关面试题

你是什么理解乐观锁和悲观锁的,具体怎么实现?

乐观锁就是在加锁前认为发生锁冲突的几率不大,在加锁的时候做的工作就不多,就不会真的加锁,而是直接尝试访问数据.在访问数据的同时便辨别当前数据是不是出现访问异常.

悲观锁就是在加锁前认为发生锁冲突的概率比较大,在进行加锁的时候做的工作就比较多,每次访问变量前都会去真正的进行加锁.

悲观锁的实现就是先加锁,获取到锁再来操作数据,获取不到锁就等待.乐观锁的实现可以引入一个版本号,借助版本号识别出当前的数据访问是不是有冲突.

介绍一下读写锁

读写锁就是把读操作和写操作分别进行加锁. 读锁与读锁之间不会发生堵塞. 读锁与写锁之间会发生堵塞.写锁和写锁之间也会发生堵塞. 这就是一个线程读的时候,另一个线程只能读不能写.而一个线程写的时候,另一个线程不能读也不能写. 一般使用读写锁的都是在读非常频繁,但写不频繁的场景下.

synchronized是可重入锁吗

synchronized是可重入锁.可重入锁是指在一个线程内,可以对同一个锁进行多次加锁,不会产生死锁.而synchronized可以重入是因为它内部有两个重要的属性,一个是记录持有这个锁的线程身份,另一个是计数器(记录加锁的次数). 如果发现当前加锁的线程就是持有锁的线程,计数器就会++.

什么是自旋锁,为什么要使用自旋锁呢,缺点是什么?

自旋锁就是当一个线程发生锁竞争后,它不会挂起等待,而是通过while来不断循环来尝试再次获取到锁.一但其他线程释放锁后它就可以立刻获取到锁. 

因为使用自旋锁在第一次获取失败后第二次获取尝试会很快来到,这样就可以快速获取到锁.

优点就是获取锁的速度快,更高效,在锁持有时间比较短且锁竞争小的场景下非常有用,却点就是如果锁竞争多且锁持有时间长的场景下就没有用了且非常浪费CPU资源,因为它一直在不断循环,做的都是无用功.


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

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

相关文章

vue中哪些数组的方法可以做到响应式

Vue2 中为什么直接通过数组的索引修改元素是不会触发视图更新 vue2 为什么不直接监听数组 Vue2 对于数组提供了一些变异方法 重写数组方法源码分析 定义拦截器将拦截器挂载到数组上面收集依赖 扩展:理解Vue2如何解决数组和对象的响应式问题 对复杂对象的处理 复杂对…

基于JSP+Servlet+Mysql的建设工程监管信息

基于JSPServletMysql的建设工程监管信息 一、系统介绍二、功能展示1.企业信息列表2.录入项目信息3.项目信息列表 四、其它1.其他系统实现五.获取源码 一、系统介绍 项目名称:基于JSPServlet的建设工程监管信息 项目架构:B/S架构 开发语言:…

ubuntu pycharm 死机,如何重启

1. 找出pycharm 进程的id 进入命令行: ps -ef 是查看当前运行的进程 值输入 ps -ef 会返回所有当前执行的进程,太多了,过滤一下,找到 pycharm : ps -ef | grep pycharm 2. 使用 kill -s 9 来杀死进程 如图所是,…

HTML基础标签

但实际上无论声明为中文还是英文都可以写&#xff0c;中文/英文 主要是浏览器在进行调用翻译功能的时候&#xff0c;会按照声明的语言来进行翻译。 标签语义&#xff1a; 标签的属性一般都是在第一个标签中定义该标签效果所拥有的属性。 即标签的作用是什么 <>标签功能…

美食大赛的题解

目录 原题描述&#xff1a; 题目描述&#xff1a; 输入格式&#xff1a; 输出格式&#xff1a; 样例输入&#xff1a; 样例输出&#xff1a; 数据规模&#xff1a; 题目大意&#xff1a; 主要思路&#xff1a; 注&#xff1a; 代码&#xff1a; 原题描述&#xff1a…

C# WPF上位机开发(crc校验)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 为了验证数据传输的过程中有没有发生翻转&#xff0c;我们在传输报文的同时一般还会添加一个crc校验。对于modbus协议也是一样&#xff0c;它在数据…

Unity中Shader URP最简Shader框架(整理总结篇)

文章目录 前言一、精简 ShaderGraph 所有冗余代码后的最简 URP Shader二、我们来对比一下 URP Shader 与 BuildInRP Shader 的对应关系 与 区别1、"RenderPipeline""UniversalPipeline"2、面片剔除、深度测试、深度写入、颜色混合 和 BRP 下一致3、必须引入…

maven工程中读取resources中的资源文件

maven工程的代码布局如下&#xff1a;在resources下面有一个资源文件test.properties&#xff0c;现在的目标要在Java代码中读取该资源文件中的内容。 test.properties资源文件的内容如下&#xff1a; Java代码如下&#xff1a; package com.thb;import java.io.BufferedR…

github 学习番外篇

我们可以按照仓库开始的提示提交仓库 不知道为什么 出现了 我用 git branch 查看了一下&#xff0c;竟然没发现分支 后来发现是只有commit以后才会显示这个分支 后来显示 这是因为本地和远程仓库不同步的原因 这时候我们就需要git pull 一下 发现两个仓库由于不关联不能git…

【算法】【动规】乘积为正数的最长子数组长度

跳转汇总链接 &#x1f449;&#x1f517;算法题汇总链接 1.1 乘积为正数的最长子数组长度 &#x1f517;题目链接 给你一个整数数组 nums &#xff0c;请你求出乘积为正数的最长子数组的长度。 一个数组的子数组是由原数组中零个或者更多个连续数字组成的数组。 请你返回乘积…

生产派工自动化:MES系统的关键作用

随着制造业的数字化转型和智能化发展&#xff0c;生产派工自动化成为了提高生产效率、降低成本&#xff0c;并实现优质产品生产的关键要素之一。制造执行系统&#xff08;MES&#xff09;在派工自动化中发挥着重要作用&#xff0c;通过实时数据采集和智能调度&#xff0c;优化生…

人工智能联盟的首件神兵利器——“Purple Llama” 项目,旨为保护工智能模型安全性

Meta公司&#xff08;Meta Platform Inc&#xff09;&#xff0c;原名Facebook&#xff0c;创立于2004年2月4日&#xff0c;市值5321.71亿美元。总部位于美国加利福尼亚州门洛帕克。 Meta 公司推出了名为“Purple Llama”的项目&#xff0c;旨在保护和加固其开源人工智能模型。…

详细了解stm32---按键

提示&#xff1a;永远支持知识文档免费开源&#xff0c;喜欢的朋友们&#xff0c;点个关注吧&#xff01;蟹蟹&#xff01; 目录 一、了解按键 二、stm32f103按键分析 三、按键应用 一、了解按键 同学们&#xff0c;又见面了o(*&#xffe3;▽&#xffe3;*)ブ&#xff0c;最…

高级前端开发工程师

岗位需求 熟练掌握前端主流框架Vue、React、Angular,至少熟练掌控Vue全家桶 文章目录 岗位需求前言一、Vue框架二、React框架三、Angular框架四、什么是Vue全家桶前言 -那就看你表哥的电脑里有没有硬盘 -我不敲键盘 一、Vue框架 Vue(读音为/vjuː/,类似于"view"…

Jenkins离线安装部署教程简记

前言 在上一篇文章基于Gitee实现Jenkins自动化部署SpringBoot项目中&#xff0c;我们了解了如何完成基于Jenkins实现自动化部署。 对于某些公司服务器来说&#xff0c;是不可以连接外网的&#xff0c;所以笔者专门整理了一篇文章总结一下&#xff0c;如何基于内网直接部署Jen…

gitlab下载,离线安装

目录 1.下载 2.安装 3.配置 4.启动 5.登录 参考&#xff1a; 1.下载 根据服务器操作系统版本&#xff0c;下载对应的RPM包。 gitlab官网&#xff1a; The DevSecOps Platform | GitLab rpm包官网下载地址: gitlab/gitlab-ce - Results in gitlab/gitlab-ce 国内镜像地…

Redis第1讲——入门简介

Java并发编程的总结和学习算是告一段落了&#xff0c;这段时间思来想去&#xff0c;还是决定把Redis再巩固和学习一下。毕竟Redis不论是在面试还是实际应用中都是极其重要的&#xff0c;在面试中诸如Redis的缓存问题、热key、大key、过期策略、持久化机制等&#xff1b;还有在实…

武林风云之linux组软raid0

小y可喜欢玩文明系列的游戏了&#xff0c;因为小y也一直喜欢造轮子&#xff0c;属于自己的轮子。 每次小y听到”要向雄鹰一样&#xff0c;定要遨游于天际。”感觉自己给自己打了一针强心剂&#xff0c;要求自己拼搏进取。 众所周知&#xff0c;文明是个原生的linux游戏&#xf…

助力工业产品质检,基于yolov5l集成CBAM注意力机制开发构建智能PCB电路板质检分析系统

AI助力工业质检智能生产制造已经有很多成功的实践应用了&#xff0c;在我们前面的系列博文中也有很多对应的实践&#xff0c;感兴趣的话可以自行移步阅读前面的博文即可&#xff0c;这里本文的核心目的就是想要基于改进的yolov5l来开发构建用于PCB电路板智能检测分析的模型&…

ssm+vue的高校智能培训管理系统分析与设计(有报告)。Javaee项目,ssm vue前后端分离项目。

演示视频&#xff1a; ssmvue的高校智能培训管理系统分析与设计&#xff08;有报告&#xff09;。Javaee项目&#xff0c;ssm vue前后端分离项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09…