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

推荐订阅源

酷 壳 – CoolShell
酷 壳 – CoolShell
T
Threatpost
Latest news
Latest news
N
News | PayPal Newsroom
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
Help Net Security
Help Net Security
D
Darknet – Hacking Tools, Hacker News & Cyber Security
AI
AI
Simon Willison's Weblog
Simon Willison's Weblog
TaoSecurity Blog
TaoSecurity Blog
The Last Watchdog
The Last Watchdog
L
LINUX DO - 热门话题
Google DeepMind News
Google DeepMind News
T
Threat Research - Cisco Blogs
O
OpenAI News
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
T
The Exploit Database - CXSecurity.com
NISL@THU
NISL@THU
Application and Cybersecurity Blog
Application and Cybersecurity Blog
S
Securelist
小众软件
小众软件
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
Martin Fowler
Martin Fowler
S
SegmentFault 最新的问题
Cisco Talos Blog
Cisco Talos Blog
云风的 BLOG
云风的 BLOG
AWS News Blog
AWS News Blog
GbyAI
GbyAI
N
News and Events Feed by Topic
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
美团技术团队
Engineering at Meta
Engineering at Meta
A
About on SuperTechFans
博客园 - 三生石上(FineUI控件)
S
Schneier on Security
博客园 - 聂微东
V2EX - 技术
V2EX - 技术
T
Troy Hunt's Blog
SecWiki News
SecWiki News
S
Secure Thoughts
B
Blog RSS Feed
Hugging Face - Blog
Hugging Face - Blog
WordPress大学
WordPress大学
腾讯CDC
H
Heimdal Security Blog
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
Apple Machine Learning Research
Apple Machine Learning Research
月光博客
月光博客
www.infosecurity-magazine.com
www.infosecurity-magazine.com
P
Privacy International News Feed

博客园 - Johnson_wang

对云服务器挂载cos桶 记录一次xxlJob升级版本导致的 xxl-job remoting error(Connection reset) 记一次NoClassDeffoundEror问题解决过程 nginx配置支持ws,并解决跨域 关于消费端接入dubbo,连接失败问题 RedisTemplate关于key出现前缀\xac\xed\x00\x05t\x00\x0f - Johnson_wang - 博客园 ES 单索引大表拆分 关于ES索引被聚合查询导致filedata堵塞 (pressure too high, (smooth) bulk request circuit break) 发送HTML格式邮件 elasticsearch报错FORBIDDEN/12/index read-only / allow delete spring Boot 相关问题以及修复(后续待补充) mybatis数据加解密处理方案 队列缓存区-db写入 Scheduler踩坑记录 关于RedisTemplate的map存储踩坑记录 关于HashMap的加载因子相关理解 Mybatis 分页插件PageHelper 遇坑 Linux 下 Mysql忘记密码重置 Eclipse MAT和jvisualvm分析内存溢出
synchronized的实现原理
Johnson_wang · 2020-09-24 · via 博客园 - Johnson_wang

Synchronized的特性

synchronized 是java中的关键字,主要用于加锁,来实现同步,具体实现形式有以下三种:

1.对普通方法加锁,锁是当前实例对象

2.对静态方法加锁,锁是当前类的Class实例,因为Class数据存在于永久代,因此静态方法锁相当于该类的一个全局锁;

3.对对象实例加锁,锁是Synchronized括号里对象实例。

synchronized 内置锁 是一种 对象锁(锁的是对象而非引用变量),作用粒度是对象 可以用来实现对临界资源的同步互斥访问 ,是可重入的。其可重入最大的作用是避免死锁,如:子类同步方法调用了父类的同步方法,如果没有可重入的特性,就会发生死锁。

Synchronized的同步实现

Synchronized的锁的实现是基于JVM进入和退出monitor对象来实现的。

monitor对象有2个关键指令monitorenter和monitorexit,具体就是在编译过程中把monitorenter指令插入到同步代码块开始位置,把monitorexit指令插入退出或异常的位置。

线程执行同步代码块的时首先需要获取锁,即尝试获取monitor对象的所有权,具体过程如下:

首先线程执行指令monitorenter指令尝试获取monitor的所有权,如果monitor的进入数为0,则线程进入进入monitor,并且把进入修改为1,当前线程就持有了锁;如果线程进入monitor时,发现进入数大于0,则会判断monitor的持有者是否为当前线程,如果是当前线程则表示只是重新进入,则对monitor的进入数+1;如果monitor的所有权不是被当前线程持有,线程进入阻塞状态,直到monitor的进入数等于0,再次重新获取monitor的所有权。

对象头

java中每个对象都包含三部分:对象头、实例数据、对齐填充(非必须)。synchronized使用的锁是存在对象的对象头中,对象头主要包含了2部分数据,Mark Word(存储对象的hashCode、分代年龄和锁标记位)、Class Metadata Address(存储对象类型数据的指针)。

锁的升级和对比

synchronized在JDK 1.6以后引入锁的状态级别,从低到高为:无锁、偏向锁、轻量级锁、重量级锁;

锁可以根据竞争进行粗话升级,但是不能降级。

偏向锁

当一个线程访问同步代码块获取锁时,会在对象头和栈帧中的锁记录中存储锁偏向的线程id,以后该线程再次进入和退出同步代码块时不需要信息CAS操作来加锁或解锁。

首先执行monitorenter命令尝试获取锁,查询Mark Word中存储的线程id是否为当前线程id,如果为当前线程id,则直接执行同步代码,如果不是当前线程id,则判断是否开启了偏向锁;

当偏向锁标识为1是,使用CAS竞争锁,竞争成功,尝试把Mark Word中的偏向锁指向自己;竞争失败,表示当前有多个线程在竞争锁,当到达全局安全点时,获得偏向锁的线程被挂起,偏向锁升级为轻量级锁,然后被阻塞在安全点的线程继续往下执行同步代码块;

偏向锁的机制:竞争时才会释放锁,线程是不会主动去释放偏向锁,需要等待其他线程来竞争。偏向锁的撤销需要 等待全局安全点(这个时间点是上没有正在执行的代码)

轻量锁

轻量锁加锁

线程在执行同步块之前,JVM会先在当前线程的栈桢中创建用于存储锁记录的空间,并将对象头中的Mark Word复制到锁记录中,官方称为DisplacedMark Word。然后线程尝试使用CAS将对象头中的Mark Word替换为指向锁记录的指针。如果成功,当前线程获得锁,如果失败,表示其他线程竞争锁,当前线程便尝试使用自旋来获取锁。

轻量锁解锁

轻量级解锁时,会使用原子的CAS操作将Displaced Mark Word替换回到对象头,如果成功,则表示没有竞争发生。如果失败,表示当前锁存在竞争,锁就会膨胀成重量级锁。

 因为自旋会消耗CPU,为了避免无用的自旋(比如获得锁的线程被阻塞住了),一旦锁升级成重量级锁,就不会再恢复到轻量级锁状态。当锁处于这个状态下,其他线程试图获取锁时,都会被阻塞住,当持有锁的线程释放锁之后会唤醒这些线程,被唤醒的线程就会进行新一轮的夺锁之争。