扯扯Java中的锁
前言
又过去了一个周末,最近陆陆续续的看了《并发编程的艺术》一书,对锁有不少感悟,这次就聊聊Java中的锁事。本文纯粹是漫谈,想到哪说到哪,但准确性肯定会保证,倘若有不正确之处,还请交流指正。
正文
作为Java开发, 说到锁第一时间想到的肯定是synchronized和juc包中的lock锁这俩兄弟,但如果眼光放开点,会发现还有很多其他的锁:集群/分布式环境下的分布式锁、mysql中的那一家子锁、操作系统中基于信号量/互斥量等构成的锁。。。上面说的是锁的应用场景,而说起锁本身,定义的类型也不少,什么悲观锁/乐观锁、独占锁/共享锁、读写锁、公平锁/非公平锁、重入锁、轻量级锁/重量级锁、自旋锁、偏向锁...
锁是干什么的?用个人的话来总结一下就是:用于控制不同访问来源对同一数据的访问顺序。也就是说锁的应用涉及到两个关键条件:不同访问来源(可以是不同线程、不同进程、不同APP)和操作同一数据(即共享的数据)。
下面对锁进行一下总结,首先按锁的实现思想分类:
悲观锁和乐观锁属于锁的实现思想,synchronized是悲观锁,而基于乐观锁思想的实现是以CAS为基础构建的lock锁,同样mysql中的锁属于悲观锁,用redis或者zk构建的分布式锁也都是悲观锁,操作系统中基于信号量/互斥量等构建起来的锁也都属于悲观锁范畴。所以用悲观锁/乐观锁的思想标准来看锁,发现各种各样的锁定义其实都在这二者的思想范围内,没有能跑出该范围的。
独占锁/共享锁(读写锁)属于锁的占用类型,有这两种分类的原因就是为了提高系统的并发能力--读不影响读,这里可以再引申一步,mysql为了进一步提高并发能力通过数据多版本使得读跟写也不冲突。其实这里就是提高并发能力的一条线:先是不管读请求还是写请求统统排队进行,后来将读写分开提高读读的效率,再后来通过数据多版本使得读写可以同时进行,后面还能再提高吗?或许参考redis的单线程内存操作是一个方向,但对于复杂数据形式和大数据量却不适合。
公平锁和非公平锁主要针对的是获取锁的方式,公平就是一起排队先排队的先获取到锁,而非公平则表示一起竞争后来的也可能先获取到锁。公平锁的应用场景很少,而且主要是通过lock锁实现的,平时基本都是用非公平锁,无他,非公平锁并发量比公平的强了不止一点。但要额外说一下,lock锁中的非公平模式并不是完全的非公平,如果两次获取不到锁则进入阻塞队列,进入阻塞队列中后,它就只能按队列中的顺序挨个获取锁了,所以lock锁中的非公平模式并不是彻头彻尾的非公平,世间尚存一丝公道。。。
重入锁和非重入锁属于锁的性质,这个很好理解,可以同一获取锁的来源能重复获取的锁就是可重入的,非可重入的场景很少,我们平时接触的基本都是可重入。可重入的实现,基本原理都是在获取到锁之后,将对象记录下来,下次再触发获取锁的操作时先比对一下当前对象与已记录对象是否是同一个,是的话则能获取到锁,锁计数+1。详情可见ReentrantLock的加锁过程。
由于synchronized锁是JVM本身自带的关键字,所以针对synchronized锁做了很多优化,偏向锁/轻量级锁/自旋锁/重量级锁等概念都是来自于此(对synchronized锁等讲解可移步博主之前写过的一/二/三系列【https://i.cnblogs.com/posts?cateId=1466867&page=1】)。其实从原理上来说,自旋锁不是锁,只是在获取不到锁时先自循环一定次数继续尝试获取锁,如果仍然获取不到再阻塞,是针对很快能获取到锁的场景进行的优化处理。
下面再来几张图梳理下思绪:
扯扯Java中的锁的更多相关文章
- 深入介绍Java中的锁[原理、锁优化、CAS、AQS]
1.为什么要用锁? 锁-是为了解决并发操作引起的脏读.数据不一致的问题. 2.锁实现的基本原理 2.1.volatile Java编程语言允许线程访问共享变量, 为了确保共享变量能被准确和一致地更新, ...
- 探究Java中的锁
一.锁的作用和比较 1.Lock接口及其类图 Lock接口:是Java提供的用来控制多个线程访问共享资源的方式. ReentrantLock:Lock的实现类,提供了可重入的加锁语义 ReadWrit ...
- java 中的锁 -- 偏向锁、轻量级锁、自旋锁、重量级锁(转载)
之前做过一个测试,详情见这篇文章<多线程 +1操作的几种实现方式,及效率对比>,当时对这个测试结果很疑惑,反复执行过多次,发现结果是一样的: 1. 单线程下synchronized效率最高 ...
- Java 中的锁
Java中的锁分类 在读很多并发文章中,会提及各种各样锁如公平锁,乐观锁等等,这篇文章介绍各种锁的分类.介绍的内容如下: 公平锁/非公平锁 可重入锁 独享锁/共享锁 互斥锁/读写锁 乐观锁/悲观锁 分 ...
- Java中的锁(转)
Java中的锁 锁像synchronized同步块一样,是一种线程同步机制,但比Java中的synchronized同步块更复杂.因为锁(以及其它更高级的线程同步机制)是由synchronized同步 ...
- java 中的锁 -- 偏向锁、轻量级锁、自旋锁、重量级锁
之前做过一个测试,详情见这篇文章<多线程 +1操作的几种实现方式,及效率对比>,当时对这个测试结果很疑惑,反复执行过多次,发现结果是一样的: 1. 单线程下synchronized效率最高 ...
- 深入理解Java中的锁
转载:https://www.jianshu.com/p/2eb5ad8da4dc Java中的锁 常见的锁有synchronized.volatile.偏向锁.轻量级锁.重量级锁 1.synchro ...
- JAVA 中无锁的线程安全整数 AtomicInteger介绍和使用
Java 中无锁的线程安全整数 AtomicInteger,一个提供原子操作的Integer的类.在Java语言中,++i和i++操作并不是线程安全的,在使用的时候, 不可避免的会用到synchron ...
- Java中的锁[原理、锁优化、CAS、AQS]
1.为什么要用锁? 锁-是为了解决并发操作引起的脏读.数据不一致的问题. 2.锁实现的基本原理 2.1.volatile Java编程语言允许线程访问共享变量, 为了确保共享变量能被准确和一致地更新, ...
随机推荐
- Java中时间加减的比较
public class TestDate{ public static void main(String[] args){try{ Date date=new Date(); DateFormat ...
- [区间+线性dp]数字游戏
题目描述 丁丁最近沉迷于一个数字游戏之中.这个游戏看似简单,但丁丁在研究了许多天之后却发觉原来在简单的规则下想要赢得这个游戏并不那么容易.游戏是这样的,在你面前有一圈整数(一共\(n\)个),你要按顺 ...
- Android 伤敌一千自损八百之萤石摄像头集成(一)
最近忙着修改萤石摄像头C3型号开头的设备添加 本来不是很复杂的事情. , 现在我感觉我入魔了 总感觉这是个小人 螺丝口是眼睛 插入SD卡的事鼻子嘴 接信号的事手 怎么看怎么像愤怒的小人 总结,先看一下 ...
- Spring事务的传播级别
一.简单说明 传播属性 描述 PROPAGATION_REQUIRED 如果当前没有事务,就创建一个事务,如果当前存在事务,就加入该事务. PROPAGATION_REQUIRED_NEW 当前的方法 ...
- MySQL 树形索引结构 B树 B+树
MySQL 树形索引结构 B树 B+树 如何评估适合索引的数据结构 索引的本质是一种数据结构 内存只是临时存储,容量有限且容易丢失数据.因此我们需要将数据放在硬盘上. 在硬盘上进行查询时也就产生了 ...
- 线性DP之免费馅饼
题目 思路 线性DP,思路很容易就能想到,f[i][k]数组定义为第i秒在k位置时从上一位置j转移过来的最优解,易得f[i][k]=max(f[i][k],f[i-1][j]+search(i,k)) ...
- DLL注入之修改PE静态注入
DLL注入之修改PE静态注入 0x00 前言 我们要注入的的力量功能是下载baidu首页数据.代码如下: #include "stdio.h" #include"stdi ...
- 5 个 IDEA 必备插件,让效率成为习惯
IDEA 是最好的 IDE,谁赞成,谁反对? IDEA 是 Java 开发人员中最受欢迎和用户友好的 IDE 之一,它具有许多便利的功能,例如智能代码完成,自动执行繁琐的重复开发任务,因此它已成为 J ...
- 龙芯开源社区上线.NET主页
龙芯团队从2019年7 月份开始着手.NET Core的MIPS64支持研发,经过将近一年的研发,在2020年6月18日完成了里程碑性的工作,在github CoreCLR 仓库:https://gi ...
- MYSQL 之 JDBC(五): 增删改查(三)PreparedStatement
是Statement的子接口,可以传入带占位符的sql语句,并且提供了补充占位符变量的方法. 使用Statement需要进行拼写SQL语句,很辛苦,很容易出错. 引号的问题处理很复杂,不利于维护. 可 ...