从细节理解锁的升级
线程同步
- 保证互斥访问,即一个对象被一个线程修改的时候,另一个线程不允许同时进行修改
- 保证进入同步方法或者同步代码块的每个线程,都能看到之前的修改效果
锁的升级
锁
以生活做类比,与锁相关的还有一些概念,比如说钥匙,柜子.钥匙用于开锁,锁用于保护柜子里的物资.只有得到了这把钥匙,我们才能去访问柜子里的资源.而锁和钥匙是一起交付的,不会出现只卖锁不卖钥匙的情形,因此正常情况下得到锁就意味着我们一定能够打开这把锁
java中的锁也是一样,只不过锁的是同步代码块,而获得锁的是线程,当一个线程获取到一个锁时也等价于获取到了该锁的钥匙.也就能访问到被锁住的代码与资源.而其他线程在此时则无法访问该块代码.
无锁
无锁就意味着,任意线程任意时刻都可以访问
偏向锁
当第一个线程第一次访问一个锁时,会通过CAS
将自己的ThreadID
置换到MarkWord
中,并将偏向锁标志位置为1,当该线程再次访问此同步代码块时首先判断是否为偏向锁,是则继续判断ThreadId
是否相同,相同就直接进入同步代码块,避免了再次用CAS
的开销,如果有第二个线程来访问同一个代码块,也会先判断是否为偏向锁以及ThreadID
是否相等,不相等则利用CAS
去替换自己的ThreadID
,如果成功,则说明第一个线程已经不在了,此时依旧为偏向锁.如果失败,说明线程一依旧占有锁,此时则将线程一暂停,设置偏向锁标识为0,并设置锁标志位为00,升级为轻量级锁,会按照轻量级锁的方式进行竞争锁。
注意
- 当一个对象已经计算过identity hash code,它就无法进入偏向锁状态;
- 当一个对象当前正处于偏向锁状态,并且需要计算其identity hash code的话,则它的偏向锁会被撤销,并且锁会膨胀为轻量级锁或者重量锁;
也就是说HashCode与偏向锁不能共存,jdk15以后似乎有取消偏向锁的趋势
轻量级锁
从无锁->轻量级锁
首先通过标志位判断此时同步块是否被锁定,如果没有被锁定,则在当前线程的栈帧中建立一个叫做Lock Record
的空间,用于存储对象(锁)当前的Mark Word
拷贝,同时还存有一个指针,然后再通过CAS
尝试把对象的MarkWord
更新为指向LockRecord
的指针(也就是说,如果此时锁对象的MarkWord
与LockRecord
里的相同,那么当前线程就可以获得锁)将LockRecord
里的另一个指针指向当前的MarkRecord
(这个用于轻量级锁的撤销),更新成功后,将锁标志位转化为00
.
如果更新失败了,就说明,有另一条线程已经获取到了锁,此时失败的线程则通过自旋来不断获取锁,如果在自旋过程中成功获取了锁,就依旧保持轻量级锁的状态,否则失败线程进入阻塞状态,将锁的标志位变为10
,MarkWord
变成指向重量级锁的指针,成为重量级锁
//Lock Record数据结构如下
class BasicObjectLock {
friend class VMStructs;
private:
BasicLock _lock;
oop _obj;
};
class BasicLock {
private:
volatile markOop _displaced_header;
};
注意
只有两条线程相互竞争的时候才会有轻量级锁的产生,若是两条以上的线程竞争,则直接膨胀为重量级锁
重量级锁
重量级锁就是最传统的锁,只有一个线程获得锁,其他所有线程阻塞等待唤醒
总结
一般所说的偏向锁->轻量级锁->重量级锁
的流程只有在不使用HashCode
且只有两个线程竞争的时候生效
如果使用hashCode
则会跳过偏向锁,超过两个线程竞争,则会直接成为重量级锁.
原文地址:https://www.cnblogs.com/GodTestLove/p/15228871.html
- memory_profiler的使用
- 使用line_profiler查看api接口函数每行代码执行时间
- GAN 的 keras 实现
- 双向 LSTM
- scrapy回调函数传递参数
- python更新数据库脚本两种方法
- 使聊天机器人具有个性
- 遇到502错误,invalid request block size 解决方法
- python中json.loads,dumps,jsonify使用
- sqlalchemy和flask-sqlalchemy几种分页操作
- 一个 tflearn 情感分析小例子
- 前端js,后台python实现RSA非对称加密
- 运行mysql时,提示Table ‘performance_schema.session_variables’ doesn’t exist
- ODL应用开发之MD-SAL中级教程
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Github Pages同步到Qcloud腾讯云对象存储COS By HKL,
- 独家 | 探索性文本数据分析的新手教程(Amazon案例研究)
- OpenWRT通过3G Modem加asterisk将GSM通话转为SIP By HKL,
- Coding通过Jenkins生成jekyll并发布到腾讯云对象存储Qcloud COS By HKL,
- mybatis 实用技巧:<trim prefix="where" prefixOverrides="and|or">
- OpenWRT配置Webdav(s)共享文件 By HKL,
- OpenWRT配置Apache Webdav By HKL,
- 我向面试官讲解了单例模式,他对我竖起了大拇指
- 47 张图带你 MySQL 进阶!!!
- 新特性解读 | InnoDB-Cluster 扫盲-日常运维
- Laravel 框架实现无限极分类
- 这样设置IDEA,让你爽到飞起!
- 这些年,我写过的BUG(一)
- Selenium处理下拉列表
- 掌握好这几个css属性,少写100行js代码