Daguai upgrade lock: easy to understand explanation biased locking, lightweight and heavyweight lock lock

PART0:

 

PART1:

First through a small example to explain the difference between three kinds of locks:

If only one bowl at home, when my own home, no one will fight and I bowl, then that is biased locking state

When my girlfriend and I were eating at home, if not hungry girlfriend, then she will wait and then I finished my bowl to eat, this is a lightweight lock status

When my girlfriend and I are very hungry, and this time it will go to fighting only a bowl (poor me) to eat, this is the heavyweight lock status

 

PART2:

I am a thread, life in the JVM (Java Virtual Machine), this period of life is somewhat boring, the whole world seems to only this one person, every day is busy executing code, a break is very difficult.

I heard that humans write code in some special place, called the critical region , such as synchronized method or block of code modification, they are very magical at the same time JVM boss allows only one thread into the implementation.

In fact, the boss set a lock, grab the lock can be executed, or only blocked, waiting for someone to release the lock.

Boss said, blocking is not working, and honestly waiting on the line.

But there are still this and other good things! Let me quickly blocked once.

But the boss said: "Every time I had to set the lock operating systems deal and asked him to maintain what Mutex (mutex) things in the kernel, he had to carry you these threads blocking, switch, this is a sum huge cost ah, these locks or less better. "

My luck is not good, I do not know how much code is executed, the number of function calls, even never once encountered a critical section!

I think perhaps accidentally when programming the programmer does not consider multithreading concurrent; also possible that most of these programs are stateless, how many threads are executed without problems.

So I had been implementing it, do not know how many days, I was so excited to find that a synchronized block of code modification finally emerged:

Account account = ...

synchronized(account){

... critical section of the code ...

}

Biased locking

I fully expected another thread has entered the block, then I can block, rest.

即使没有其他线程进入临界区,老大为我申请锁, 也得和操作系统协商什么互斥量,从用户态进入核心态,再从核心态返回用户态,总要花些功夫吧。

可是老大根本没有去找操作系统, 只是看了看这个account对象的所谓“对象头”,其中有个叫做Mark Word的东西,似乎是个什么数据结构, 里边有几个标识位,还有其他数据。

老大随手使用CAS操作把我的线程ID记录到了这个Mark Word当中,修改了标识位,然后告诉我说: 可以了,你现在拥有这把锁了,进去执行代码吧。

我惊奇地说:“老大你不和操作系统协商设置Mutex了?”

老大说:“不用了,你看现在就你一个线程进入了这个代码块,我只要记录下你的线程ID,就表示你拥有这把锁了,不用操作系统介入。”

我获得了锁,开始执行被synchronized包裹的代码块。

等到我第二次执行到这个synchronized的时候,老大只是看了一眼锁对象account的Mark Word就说:“你的线程ID还在,还持有着这个对象的锁,进入临界区执行吧。”

我连喘口气的机会都没有,只好继续执行。

老大说,这叫偏向锁,在没有别的线程竞争的时候,一直偏向我,可以让我一直执行下去。

我是多么期盼来一个新的线程来和我竞争啊!

轻量级锁

很快,机会就来了。

另外一个线程0x3704也要进入这个代码块执行,但是锁对象account 保存的是我的线程ID,他是没法进入临界区的。

我心想,我们两个至少得有一个进入阻塞状态,休息一会儿了。

但是老大还是不去操作系统协商,只是说: 我把这个偏向锁升级一下,变成一个轻量级的锁吧。

老大把锁对象account恢复成无锁状态,在我们俩的栈帧中各自分配了一个空间,叫做Lock Record, 把锁对象account的Mark Word在我们俩这里各自复制了一份,叫做Displaced Mark Word, 这名字真奇怪。

然后把我的Lock Record的地址使用CAS放到了Mark Word当中,并且把锁标志位改为00, 这其实就意味着我也已经获得了这个轻量级的锁了,可以继续进入临界区执行。

0x3704没有获得锁,但还是不阻塞,老大让他自旋几次,等待一会儿。

等到我退出临界区,释放锁的时候,需要把这个Displaced markd word 使用CAS复制回去。接下来他就可以加锁了。

我们两个交替着进入临界区,执行这段代码,相安无事,很少出现真正的竞争。

即使是出现了竞争,想获得锁的线程只要自旋几次,等待一会儿,锁就可能释放了。

很明显,如果没有竞争或者轻度的竞争,轻量级锁仅仅使用CAS操作和Lock record就避免了重量级互斥锁的开销,对JVM老大来说,确实是个好主意。

重量级锁

轻量级锁运行得挺好,我还是没有机会休息,终于有这么一天,0x3704 正在持有锁,在临界区辛苦地执行代码。 我自旋了好多次,0x3704还是没释放锁。 这时候JVM老大说: 自旋次数太多了,太浪费CPU了,接下来升级为重量级锁!

这个重量级锁需要操作系统的帮忙,依赖操作系统底层的Mutex Lock。

只见老大创建了一个monitor 对象, 把这个对象的地址更新到了Mark word当中。

锁升级了!

由于0x3704还在持有锁运行,而我终于进入了梦寐以求的状态:阻塞! 终于可以休息一下了!

仔细一想,老大煞费心机地设置了偏向锁和轻量级锁,就是为了避免阻塞,避免操作系统的介入, 这两种锁无非就是针对这两种情况:

偏向锁: 通常只有一个线程在临界区执行

轻量级锁: 可以有多个线程交替进入临界区,在竞争不激烈的时候,稍微自旋等待一下就能获得锁。

至于重量级锁,也是我最为期待的锁,那就是出现了激烈的竞争,只好让我们去阻塞休息了。

-END-

发布了302 篇原创文章 · 获赞 1840 · 访问量 1419万+

Guess you like

Origin blog.csdn.net/z69183787/article/details/104495882