惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

SecWiki News
SecWiki News
I
InfoQ
The Cloudflare Blog
人人都是产品经理
人人都是产品经理
博客园 - Franky
T
Tailwind CSS Blog
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
量子位
博客园_首页
罗磊的独立博客
V
V2EX
李成银的技术随笔
大猫的无限游戏
大猫的无限游戏
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
T
True Tiger Recordings
Vercel News
Vercel News
Cyberwarzone
Cyberwarzone
Cisco Talos Blog
Cisco Talos Blog
F
Fox-IT International blog
D
Darknet – Hacking Tools, Hacker News & Cyber Security
M
Microsoft Research Blog - Microsoft Research
Know Your Adversary
Know Your Adversary
爱范儿
爱范儿
The Register - Security
The Register - Security
G
Google Developers Blog
The Hacker News
The Hacker News
Malwarebytes
Malwarebytes
S
Securelist
博客园 - 三生石上(FineUI控件)
Jina AI
Jina AI
T
Threat Research - Cisco Blogs
T
The Exploit Database - CXSecurity.com
S
SegmentFault 最新的问题
博客园 - 叶小钗
F
Fortinet All Blogs
Apple Machine Learning Research
Apple Machine Learning Research
宝玉的分享
宝玉的分享
博客园 - 聂微东
T
Threatpost
博客园 - 【当耐特】
D
Docker
P
Privacy & Cybersecurity Law Blog
www.infosecurity-magazine.com
www.infosecurity-magazine.com
G
GRAHAM CLULEY
V
Visual Studio Blog
C
Cisco Blogs
IT之家
IT之家
S
Security Archives - TechRepublic
Latest news
Latest news
阮一峰的网络日志
阮一峰的网络日志

青空之蓝

[青空之蓝-2023] - 色彩 | 青空之蓝 [青空之蓝-2022] - 平静 | 青空之蓝 [青空之蓝-2021] - 远望 | 青空之蓝 浅谈垃圾回收 | 青空之蓝 浅谈泛型擦除 浅谈单点登录 使用 Kotlin 编写 Spring 测试 设计模式系列文章 从零实现一个 Java 微框架 - IoC | 青空之蓝 从零实现一个 Java 微框架 - 前言 浅谈 JVM:类加载 浅谈 IO 浅谈并发:synchronized & ReentrantLock 浅谈并发:CAS & AQS 浅谈并发:ThreadLocal 浅谈并发:三大特性 浅谈组合注解 & 注解别名 [青空之蓝-2020]-迷茫 Java 系列文章 HTTP 系列文章 | 青空之蓝 浅谈 EatWhatYouKill 浅谈可扩展线程池 聊聊写框架 | 青空之蓝 聊聊现状-[2020-09] | 青空之蓝 浅谈并发:基础 | 青空之蓝 浅谈缓存 | 青空之蓝 无须定义类,Spring 快速注入 Json 参数 浅谈 Proxy 和 Aop 从零实现一个 PHP 微框架 - 初始化请求 为 Vue3 添加一个简单的 Store 从零实现一个 PHP 微框架 - 服务提供者 WSL2 踩坑记录 浅谈浏览器Event Loop [更新] | 青空之蓝 从零实现一个 PHP 微框架 - Bootstrap 启动加载 从零实现一个 PHP 微框架 - IoC 容器 从零实现一个 PHP 微框架 - PSR & Composer 从零实现一个 PHP 微框架 - 前言 MVVM 简单实现 浅谈 DI 和 IoC 中间件实现 [PHP] 告别 Windows 终端的难看难用,打造好用的 PowerShell VSCode Java输出中文乱码问题解决[更新] 浅谈浏览器渲染 Vue-Cli@2 项目迁移日志 Laragon & Scoop 集成踩坑记录 「一行代码」优雅管理 Windows 软件 [青空之蓝-2019]-年度总结 为Vue添加简单的Store 为React添加简单的Store 为Vuex添加同步Action 浅谈B+树 浅谈跳表 浅谈数据库索引 | 青空之蓝 MySQL事务隔离 算法复杂度分析(1) 一年来的经验总结 Acrylic - VSCode Extension ace编辑器设置惯性滚动 为apt方式安装的nginx重新编译增加WebDAV Java二叉树实现 Java图实现 XK-Editor - 一个支持富文本和Markdown的编辑器 JS生成列表树 | 青空之蓝 Laravel生成目录树 XK-Note - 集各种神奇功能的云笔记 PHP GD生成验证码 PHP GD图片处理[转换格式-水印-缩略图] | 青空之蓝 Origami - 简洁轻快的WordPress主题 为WordPress启用WorkBox Windows IP变化自动发送邮件 [青空之蓝-2018]-年度总结 VSCode Java手动导入jar和源码包 C 结构体的定义和使用 | 青空之蓝 C链表实现重制版 | 青空之蓝 图的搜索(遍历) - BFS & DFS Java链表实现 | 青空之蓝 C 快速排序 | 青空之蓝 C 归并排序 C 插入排序 C语言链表实现 VSCode配置Java调试环境[Windows] C 选择排序 C 冒泡排序 VSCode配置PHP调试环境[Windows] | 青空之蓝 VSCode配置C/C++ GDB调试环境[Windows] WordPress友情链接模板 Intel Optane 傲腾内存体验 | 青空之蓝 Mysql双机热备实战 博客一年记录 为WordPress启用Service Worker Bing每日一图API iframe延迟加载 写在2018年高考前 The Fox主题汉化分享 [青空之蓝-2017]-崭新 本博客评论规则 世界,您好!
浅谈并发:锁 | 青空之蓝
2020-08-26 · via 青空之蓝

浅谈并发:锁

前言

接着写浅谈系列。

这次要聊的是锁,锁在并发编程中扮演着非常重要的角色,Java 中提供了多种类型的锁,不同类型的锁在不同的场景中都有不同的性能表现。

锁的类别

锁可以按照特性进行分类,分类后我们就可以较为直观的区分不同的锁和区别不同锁的不同特性。

锁的对比

分类了锁后,我们就可以对其进行对比分析了。

悲观锁 & 乐观锁

对于一个数据的并发操作,悲观锁总是认为自己在使用数据的时候别的线程会来修改数据,所以为了防止被修改,在获取数据的时候会对该数据进行加锁操作,确保只有取得锁的线程能对此数据进行操作。

与之相反,乐观锁总是认为自己在使用数据的时候别的线程不会来修改数据,所以也就不需要加锁,通常是使用 CAS 操作,在更新的时候通过比较判断数据是否被修改,如果没有被修改,则更新成功,如果被修改则进行报错或重试。

悲观锁更适合写多读少的场景,读取操作并不会改变数据,所以如果用在读取多的场景下则会造成严重的性能浪费。

乐观锁则更适合写少读多的场景,由于乐观锁一般是采用 CAS(比较并替换)的实现方式,每次写入操作的时候都要复制一份原始数据,而这操作是非常耗能的,用在写入少的场景下就不如使用悲观锁了。而读取的时候并不会加锁,这也就意味着可以并行的读取,所以在读取的方面上有非常好的性能。

非自旋锁 & 自旋锁

自旋指的是在获取数据失败后是采用进行循环重试而不是休眠线程等待锁的释放。

通常情况下,锁住某个资源的时间都是很短的,如果为了这点时间挂起线程恢复线程,则有可能得不偿失。在这种场景下,我们可以进行循环尝试,一旦锁释放了,那么就可以立即对数据进行操作,而不需要再等待线程的唤醒。

不过自旋也是有缺点的,由于是循环尝试,所以虽然避免了线程的切换,但需要占用处理器时间,所以一般都是进行一定范围的尝试,超出了范围后切换成阻塞。

公平锁 & 非公平锁

公平锁是指线程获取锁的先后顺序是按照申请锁时的先后顺序排序的。

非公平锁下的线程会先尝试一下获取锁,如果刚好锁被释放了,那么这个线程就可以直接获取锁,而无需进行排队。当第一次获取的时候无法获取到的时候才会进入排队的状态。

公平锁下不会出现线程饿死(无限等待)的情况,但是缺点也很明显,每个线程都需要阻塞等待,而阻塞和唤醒的开销并不小。

非公平锁由于可以插队,如果刚好可以获取到锁的话就不需要阻塞和唤醒了,减少了部分的开销,整体的并发性能较好。但是由于可以插队,那么就有可能会出现部分线程长时间处于等待的状态,或者是饿死的情况。

可重入锁 & 不可重入锁

可重入锁和不可重入锁的区别在于一个线程是否可以再次获取该锁。不可重入锁容易发生死锁的问题。

Java 中的 ReentrantLock 和 synchronized 都是可重入锁,NonReentrantLock 是不可重入锁。

共享锁 & 排他锁

故名思意,共享锁就是当一个线程获取该锁的时候,另外一个线程也可以获取这个锁。

排他锁则相反,当一个线程获取该锁的时候,另外一个线程不可获取该锁。

共享锁一般用于读取操作,而排他锁一般用于写入操作。在 Java 中 ReentrantReadWriteLock 就是读写分离的锁,里面有 ReadLock 和 WriteLock 两把锁。读锁采用的是共享锁,再并发的时候可保证高效的并发,写锁采用排他锁,确保写操作的互斥。

无锁 & 偏向锁 & 轻量级锁 & 重量级锁

这四个锁指的是锁的状态,是 synchronized 的 4 种锁状态。

无锁就是对数据进行锁定操作,所有的线程都可以修改数据,一般是使用 CAS 等操作来保证线程安全。无锁由于不需要对线程进行休眠和唤醒,在一些场景下的性能是很好的。

偏向锁指的是一段代码一直被某个线程获取,那么这个线程就会自动获取锁。当再次操作的时候就看看偏向锁是否指向该线程,如果是,则不需要加锁操作了。

轻量级锁可以认为就是自旋锁,当锁处于轻量级锁的状态时,线程尝试获取锁失败的时候不会进入阻塞状态,而是会循环尝试。

重量级锁就是非自旋锁,当获取锁失败的时候,线程会进入阻塞的状态。

从无锁到重量级锁,其对应的额外消耗是逐渐递增的。

锁的升级 & 降级

所谓的升级和降级其实是 JVM 对 synchronized 的优化策略,在合适的场景使用合适的锁,而不是直接使用重量级锁。

无锁 <=> 偏向锁

当线程访问同步数据的时候就会将锁升级成偏向锁。

当 JVM 处于全局安全点(在这个时间点上没有正在执行的字节码)的时候会将偏向锁撤销,恢复成无锁的状态。

偏向锁 => 轻量级锁

当锁处于偏向锁的情况下,没有持有偏向锁的线程尝试获取锁时,偏向锁就会被撤销,同时锁升级成轻量级锁。

轻量级锁无法降级。

轻量级锁 => 重量级锁

当自旋超过一定指定的范围,或者是一个线程持有锁,一个线程在自旋,这时又有第三个线程尝试获取锁时,锁就会升级成重量级锁。

重量级锁无法降级。

结语

又是一篇水文 ?,本文主要是简单概述下锁的一些类别和升降级流程,所以有很多细节的地方并未说明,比如 Java 的对象头,所以,如果要更加深入的了解的话还是要另外阅读一些高质量的文章或书籍。文章不写这些主要是我不太精通,写出来的效果不好 ?。

浅谈并发:锁

https://blog.ixk.me/post/talking-about-concurrent-locks
  • 许可协议

    BY-NC-SA

  • 本文作者

    Otstar Lin

  • 发布于

    2020/08/26

转载或引用本文时请遵守许可协议,注明出处、不得用于商业用途!

聊聊现状-[2020-09]浅谈并发:基础