Java线程里的14种锁_java 线程安全 锁-程序员宅基地

技术标签: java  

 参考资料:

  1. 不可不说的Java“锁”事
  2. java多线程的15种锁

以下内容是参考上面两片文章写出的粗略总结, 想要细究可以看上面两位大佬写的文章, 由于是参考着写的, 所以有很多地方相同, 如果有侵权或不妥的地方还请联系删除.


一. 线程是否同步资源?

1. 悲观锁 : 同步

每次拿数据都按照 最坏 的情况来定, 认为一定会有别的线程过来修改, 所以每次拿数据之前都会先上锁, 这样别的线程要想来拿这个数据的时候就会被阻塞, 直到这个线程解锁. 

部分锁实现: 

synchronized 的实现就是悲观锁, 主要用于多写的场景, 可以确保数据同步正确

存在的部分问题: 

  • 线程持有该锁会导致其他需要此锁的线程阻塞
  • 竞争强烈的情况下, 不断的加锁和解锁都会影响cpu的调度从而出现性能问题
  • 如果一个优先级高的线程等待一个优先级低的线程释放锁会导致优先级倒置从而出现性能问题

2. 乐观锁 : 不同步

每次拿数据都按照 最好 的情况来定, 认为不会有别的线程过来修改, 所以每次拿数据之前都不会上锁, 但是会在更新数据的时候判断有没有别的线程去修改了这个数据.

部分锁实现: 

CAS算法, 主要用于多读的场景, 以此来提高数据的吞吐量

存在的部分问题: 

  • CAS只能保证单个变量操作的原子性,当涉及到多个变量时,CAS是无能为力的
  • 乐观锁在执行更新时频繁失败,就需要不断重试,从而浪费cpu资源
  • ABA问题

CAS (Compare And Swap) 比较和交换 : 用来保证数据操作的原子性

CAS包含了三个值: 

需要读写的内存值 V

进行比较的值 A

要写入的新值 B

一条线程想要对V修改为B, 那么在进程刚进入的时候就会让A=V, 然后在修改之前会进行判断, 如果此时的A==V, 那么就说明没有线程对V的值进行修改, 就会把B赋值给V, 如果出现了A!=V的情况, 就说明了有其他线程对V的值进行了修改, 那么就不会进行赋值, 而是会不断的自旋, 直到V==A.

但是CAS算法也存在一个非常明显的问题, 即:

ABA问题

ABA又是什么呢? 例如, 线程把数据从A修改为了B, 然后又把B修改成了A, 这样另一条线程读取的时候, 就会误认为数据一直是A, 没有变化, 从而忽略了过程.

但是ABA问题的解决方法也非常的简单: AtomicStampedReference

即在每次修改的时候添加一个版本号, 每次更新的时候都把版本号增加, 以此来解决ABA问题.

二. 同步资源失败, 是否要阻塞?

1. 阻塞

当一个线程在获取锁的时候, 如果该锁已被其他线程获取了, 那么该线程会切换至阻塞状态, 直到被唤醒.

2. 自旋锁 : 不阻塞

当一个线程在获取锁的时候, 如果该锁已被其他线程获取了, 那么该线程会进入一个循环自旋的状态, 不断尝试重新获取, 直到成功, 自旋锁的实现原理也来自CAS.

存在的部分问题:

  • 虽然避免了切换线程状态的开销, 但是它要占用cpu的时间, 如果长时间的自旋会白白浪费cpu的调度

3. 适应性自旋锁 : 不阻塞

适应性自旋锁是在jdk1.6之后引入的, 意味着自旋的次数将不再固定, 而是由上一次在该锁上的自旋时间和拥有者的状态共同决定的, 即如果有一个线程刚获得过该锁, 并且该线程还在运行中, 那么虚拟机就会认为这次自旋成功的概率也很大, 从而允许它自旋更长的时间, 反之如果一个某个锁, 很少被线程成功获得过, 那么对应的就会减少获取该锁线程的自旋时间甚至直接进入阻塞状态, 从而来避免cpu资源浪费.

三. 多个线程竞争同步资源的流程细节

这四种锁匙指锁的状态, 专门针对synchronized的

1. 无锁

没有锁住资源, 所有线程都能访问并修改同个资源, 但同一时间里只有一个能修改资源成功, 其他线程会循环重试, 直至修改成功.

CAS的原理就是无锁的实现, 无锁无法全面替换有锁, 但无锁在某些场合下的性能非常高.

2. 偏向锁

指一段同步代码一直被一个线程访问, 那么该线程会自动获取锁, 降低获取锁的代价.

大多数情况下, 锁总是由同一线程多次获得, 不存在多线程竞争, 所以出现了偏向锁, 其目的就是为了提高只有一条线程执行同步代码块的时候能够提高效率, 偏向锁只在遇到其他线程尝试竞争偏向锁的时候, 持有偏向锁的线程才会释放锁.

3. 轻量级锁

当偏向锁被另外的线程访问时, 就会升级为轻量级锁, 其他线程会通过自旋的形式来尝试获取锁, 不会阻塞, 从而提高性能.

4. 重量级锁

当轻量级锁的自旋超过一定次数, 或者又有第三个线程来拿锁的时候, 就会升级成重量级锁, 此时在等待锁的所有线程都会进入阻塞状态

四. 多个线程竞争时是否要排队

1. 公平锁 : 排队

指多个线程安装申请锁的顺序来获取锁, 线程直接进入队列中排队. 优点是等待锁的线程不会饿死, 缺点时整体吞吐效率相对非公平锁要低, 队列中除了第一个线程, 其他线程都会进入阻塞状态, CPU唤醒阻塞线程的开销比非公平锁大.

2. 不公平锁 : 不排队

指多个线程加锁时可以直接尝试获取该锁, 获取不到才会进入队列排队, 但如果刚好锁可用, 则会直接插队获取锁, 无须阻塞等待, 所以非公平可能会出现后申请先获得的情况. 非公平锁优点是可以减少唤醒线程的开销, 整体吞吐量高, 但是缺点也会导致等待队列中的线程要等待很久才会获得锁, 或者饿死.

公平锁和非公平锁的源代码中唯一的区别就在于公平锁在获取锁的时候多了一个限制条件: hasQueuedPredecessors(), 用于判断当前线程是否处于队列的第一个.

五. 一个线程中的多个流程能否获取同把锁

1. 可重入锁 : 能

指同一个线程在外层方法获取锁的时候, 再进入该线程的内层方法时, 会自动获取锁 (前提得是同一个锁对象), 不会因为外层已经获取过且还没有释放而导致阻塞.

部分锁实现:

ReentrantLock和synchronized都是可重入锁, 优点是可以一定程度上避免死锁的出现

2. 不可重入锁 : 不能

不可重入锁与之对立, 当同一个线程在外层获取到锁的时候, 再进入内层, 会导致内层一直在等待外层释放锁, 而外层又在等待内层执行, 无法释放锁, 从而出现死锁.

六. 多个线程能否共享一把锁

1. 共享锁 : 能

指当一个线程获取该锁后, 其他锁依旧可以对数据进行读取操作, 但是只有获取该锁的线程能对数据进行改写的操作

2. 互斥锁 : 不能

指当一个线程获取该锁后, 其他锁将不能对数据进行读写操作, 只有获取到该锁的线程可以对数据进行读写

以上的内容的是个人的一个总结, 水平有限, 可能不一定正确, 这篇文章仅对Java几个线程锁进行了一个初步的理解, 并没有深入探究, 如有错误还请多多包涵.

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_55415995/article/details/120962142

智能推荐

九大角度全方位对比Android、iOS开发_ios 开发角度-程序员宅基地

文章浏览阅读784次。发表于10小时前| 2674次阅读| 来源TechCrunch| 19 条评论| 作者Jon EvansiOSAndroid应用开发产品编程语言JavaObjective-C摘要:即便Android市场份额已经超过80%,对于开发者来说,使用哪一个平台做开发仍然很难选择。本文从开发环境、配置、UX设计、语言、API、网络、分享、碎片化、发布等九个方面把Android和iOS_ios 开发角度

搜索引擎的发展历史

搜索引擎的发展历史可以追溯到20世纪90年代初,随着互联网的快速发展和信息量的急剧增加,人们开始感受到了获取和管理信息的挑战。这些阶段展示了搜索引擎在技术和商业模式上的不断演进,以满足用户对信息获取的不断增长的需求。

【Elasticsearch<一>✈️✈️】简单安装使用以及各种踩坑

本地实现 Elasticsearch、kibana 管理工具、IK 分词器 的安装部署以及初步使用(以及填坑策略)

Word插件开发

创建一个新的 Office 插件项目:在 Visual Studio 中,选择"文件" -> “新建项目”,然后在模板中选择"Office/SharePoint",选择适当的 Office 插件项目模板,如 Word 插件、Excel 插件或 PowerPoint 插件。设计用户界面:在解决方案资源管理器中,打开你的插件项目,并在其中打开相应的 Office 文件(如 Word 文件、Excel 文件或 PowerPoint 文件)。你可以在 Office 应用中测试插件的功能,并在开发过程中进行调试。

便携式iv检测仪解析

在应用场景方面,便携式IV功率测试仪广泛应用于光伏电站的日常运维、光伏组件生产过程中的质量控制以及光伏项目的前期评估等环节。在光伏电站运维中,定期对光伏组件进行IV测试,可以及时发现性能下降或损坏的组件,为电站的运维提供有力支持。首先,从工作原理来看,光伏电站便携式IV功率测试仪通过模拟太阳光照射光伏组件,并测量组件在不同电压下的电流输出,从而绘制出IV曲线。此外,测试仪还可以计算光伏组件的功率输出、转换效率等参数,为用户提供全面的性能评估。

postgresql 索引之 hash_load_categories_hash postgres-程序员宅基地

文章浏览阅读3.6k次。os: ubuntu 16.04postgresql: 9.6.8ip 规划192.168.56.102 node2 postgresqlhelp create indexpostgres=# \h create indexCommand: CREATE INDEXDescription: define a new indexSyntax:CREATE [ UNIQUE ..._load_categories_hash postgres

随便推点

FRP搭建内网穿透(亲测有效)_locyanfrp-程序员宅基地

文章浏览阅读5.7w次,点赞50次,收藏276次。FRP搭建内网穿透1.概述:frp可以通过有公网IP的的服务器将内网的主机暴露给互联网,从而实现通过外网能直接访问到内网主机;frp有服务端和客户端,服务端需要装在有公网ip的服务器上,客户端装在内网主机上。2.简单的图解:3.准备工作:1.一个域名(www.test.xyz)2.一台有公网IP的服务器(阿里云、腾讯云等都行)3.一台内网主机4.下载frp,选择适合的版本下载解压如下:我这里服务器端和客户端都放在了/usr/local/frp/目录下4.执行命令# 服务器端给执_locyanfrp

UVA 12534 - Binary Matrix 2 (网络流‘最小费用最大流’ZKW)_uva12534-程序员宅基地

文章浏览阅读687次。题目:http://acm.hust.edu.cn/vjudge/contest/view.action?cid=93745#problem/A题意:给出r*c的01矩阵,可以翻转格子使得0表成1,1变成0,求出最小的步数使得每一行中1的个数相等,每一列中1的个数相等。思路:网络流。容量可以保证每一行和每一列的1的个数相等,费用可以算出最小步数。行向列建边,如果该格子是_uva12534

免费SSL证书_csdn alphassl免费申请-程序员宅基地

文章浏览阅读504次。1、Let's Encrypt 90天,支持泛域名2、Buypass:https://www.buypass.com/ssl/resources/go-ssl-technical-specification6个月,单域名3、AlwaysOnSLL:https://alwaysonssl.com/ 1年,单域名 可参考蜗牛(wn789)4、TrustAsia5、Alpha..._csdn alphassl免费申请

测试算法的性能(以选择排序为例)_算法性能测试-程序员宅基地

文章浏览阅读1.6k次。测试算法的性能 很多时候我们需要对算法的性能进行测试,最简单的方式是看算法在特定的数据集上的执行时间,简单的测试算法性能的函数实现见testSort()。【思想】:用clock_t计算某排序算法所需的时间,(endTime - startTime)/ CLOCKS_PER_SEC来表示执行了多少秒。【关于宏CLOCKS_PER_SEC】:以下摘自百度百科,“CLOCKS_PE_算法性能测试

Lane Detection_lanedetectionlite-程序员宅基地

文章浏览阅读1.2k次。fromhttps://towardsdatascience.com/finding-lane-lines-simple-pipeline-for-lane-detection-d02b62e7572bIdentifying lanes of the road is very common task that human driver performs. This is important ..._lanedetectionlite

【数据结构】静态表查找之顺序查找、二分查找、分块查找_读取表元是什么意思-程序员宅基地

文章浏览阅读4.1k次,点赞8次,收藏23次。​通过一定的方法找出与给定关键字相同的数据元素的过程叫做查找。也就是根据给定的某个值,在查找表中确定一个关键字等于给定值的记录或数据元素。_读取表元是什么意思

推荐文章

热门文章

相关标签