开释锁和锁降级基本就没懂 这都是啥
乐观锁和乐观锁
乐观锁:读、写都加锁。默认每个资源都有很多线程争抢,取得了资源就先加上锁再操作,然而加锁和开释老本高。
乐观锁:读不加锁,写加锁。
cas
compare and swap
默认没有线程和本人争抢资源,先记下操作前的快照,操作完起初比照下资源是否被批改过,如果没人来过,就写入新值,否则从新执行方才的操作。
这里存在 aba 的问题,即“尽管还是方才存起来的值,但这段时间里,有人改过两次又改回原值”,这时就会有谬误。
依据版本号判断能够解决这个问题。
java 对象头
对象头蕴含 markword、类型指针、数组长度三局部。
markword 有:指向栈中锁记录的指针、偏差线程 id、锁状态等信息。
通过 markword 内容,能够看出对象处于无锁还是偏差锁、轻量级锁、重量级锁。
多线程下 synchronized 的加锁就是对同一个对象头中 markword 中的变量进行 cas 操作。
偏差锁
很多时候一个加了锁的代码块从头至尾都只有一个线程拜访,此时用偏差锁,能够节俭加锁解锁的开销。
当这个线程持有锁之后,只有没有线程来竞争这个锁,他将始终持有锁,每次执行加锁代码块块前后,只有看看 markword 里记录的“持有偏差锁的线程”是不是本人就行。
当产生竞争时,偏差锁会降级变成轻量级锁。
轻量级锁
线程 a 和 b 竞争对象的锁。
1. 抢锁就是 cas 的改 markword,谁改胜利了,谁就抢到了。(把无锁的 markword 改成指向本人栈中锁记录的指针,旧的 markword 记在本人的栈帧里)
2. 没有抢到锁的线程,自旋(重试)等着抢到锁的线程开释锁。所以轻量级锁实用于锁粒度小,很快就开释了场景,能够省下加锁解锁的开销。锁粒度太大的话,自旋很占 cpu 资源,不如用重量级锁。
3. 如果自旋 n 次完结之后资源还是没有开释,轻量级锁就收缩成重量级锁,这个线程挂起,接下来想竞争这个资源的线程,间接挂起。
10 重量级锁
synchronized
是通过对象外部的一个叫做监视器锁(monitor
)来实现的,监视器锁自身依赖底层的操作系统的 Mutex Lock
来实现。操作系统实现线程的切换须要从用户态切换到外围态,老本十分高。这种依赖于操作系统 Mutex Lock
来实现的锁称为重量级锁。为了优化 synchonized
,引入了 轻量级锁
, 偏差锁
。