博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【synchronized底层原理之2】悲观锁与乐观锁、线程阻塞的代价等
阅读量:6912 次
发布时间:2019-06-27

本文共 1363 字,大约阅读时间需要 4 分钟。

hot3.png

悲观锁与乐观锁

悲观锁(Pessimistic Lock)

悲观锁是就是悲观思想,即认为写多,遇到并发写的可能性高,每次去拿数据的时候都认为别人会修改,所以每次在读写数据的时候都会上锁,这样别人想读写这个数据就会block直到拿到锁。由于数据进行加锁,期间对该数据进行读写的其他线程都会进行等待。

synchronized的重量级锁就是悲观锁。AQS框架下的锁则是先尝试cas乐观锁去获取锁,获取不到,才会转换为悲观锁,如RetreenLock。

乐观锁(Optimistic Lock)

乐观锁是一种乐观思想,即认为读多写少,遇到并发写的可能性低,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,采取在写时先读出当前版本号,然后加锁操作(比较跟上一次的版本号,如果一样则更新),如果失败则要重复读-比较-写的操作。由于数据没有进行加锁,期间该数据可以被其他线程进行读写操作。

java中的乐观锁基本都是通过CAS操作实现的,CAS是一种更新的原子操作,比较当前值跟传入值是否一样,一样则更新,否则失败。

synchronized的偏向锁和轻量级锁就是乐观锁

★小结

在Java技术发展史上,最开始使用的是悲观锁,实践中发现使用悲观锁有很多缺点,所以又引入了乐观锁。

两种锁各有优缺点,读取频繁使用乐观锁(但是可能出现“脏”读),写入频繁使用悲观锁(上下文切换开销大,但是保证没有“脏”数据)。

synchronized的重量级锁就是悲观锁

synchronized的偏向锁和轻量级锁就是乐观锁

java线程阻塞的代价--主要是上下文切换

Java线程的上下文切换需要操作系统的介入

java的线程是映射到操作系统原生线程之上的,如果要阻塞或唤醒一个线程就需要操作系统介入。

操作系统切换线程需要在用户态与内核态之间切换:因为用户态和内核态内存空间各自独立,故而切换要传递变量和参数,这样的话系统消耗较大,费时

需要在用户态与内核态之间切换,这种切换会消耗大量的系统资源,因为用户态与内核态都有各自专用的内存空间,专用的寄存器等,用户态切换至内核态需要传递给许多变量、参数给内核,内核也需要保护好用户态在切换时的一些寄存器值、变量等,以便内核态调用结束后切换回用户态继续工作。

频繁的上下文切换很费时,如果同步代码执行所需时间比上下文切换时间都要短,那引入重量级锁切换上下文这种同步策略是失败的:所以synchronized从JKD1.6进行了改进,引入了偏向锁、轻量级锁

java对象头中的markword

markword是java对象数据结构中的一部分,对象的markword和java各种类型的锁密切相关。

markword数据的长度在32位和64位的虚拟机(未开启压缩指针)中分别为32bit和64bit,它的最后2bit是锁状态标志位,用来标记当前对象的状态,对象的所处的状态,决定了markword存储的内容,如下表所示

32位虚拟机在不同状态下markword结构如下图所示

了解了markword结构,有助于了解java锁的加锁解锁过程。

转载于:https://my.oschina.net/u/3866531/blog/2046372

你可能感兴趣的文章
创建VLAN、中继链路和参与以太网捆绑的详细配置和截图
查看>>
健康的办公族作息时刻表
查看>>
新博客地址此博客不再更新baishuchao.github.io
查看>>
Git问题Everything up-to-date解决
查看>>
淘宝Tengine安装指南
查看>>
nginx-mysql-php安装配置
查看>>
div加链接 html给div加超链接实现点击div跳转的方法
查看>>
layer 旋转
查看>>
菜鸟学Linux 第016篇笔记 bash脚本之文件测试,变量类型
查看>>
Vue cli 资源文件的引用
查看>>
OCP知识点讲解 之 Undo回滚基础知识
查看>>
跨碧岭观赏龙潭瀑布群
查看>>
Windows 命令打开无线WIFI热点
查看>>
编写一个算法,若M*N矩阵中某个元素为0,则将其所在的行与列清零。
查看>>
写一个算法计算n的阶乘末尾0的个数
查看>>
投资“杠杆”,你了解吗?
查看>>
知其所以然之永不遗忘的算法
查看>>
Java正则表达式语法大全
查看>>
apache设置自定义header
查看>>
点乘和叉乘在3D中的实际用法
查看>>