Daguaiは、ロックをアップグレード:説明偏っロック、軽量かつヘビー級ロックロック分かりやすいです

PART0:

 

パート1:

ロックの3種類の違いを説明することは、小さな例〜第:

家庭、自分の家に1つだけのボウルは、誰が戦うんだろうと私はロック状態にバイアスされていること、その後、ボウル場合

私のガールフレンドと私は家で食べていたときに空腹のガールフレンドでない場合は、その後、彼女が待っていますし、私は、これは軽量ロック状態で、食べて、私のボウルを終え

私のガールフレンドと私は非常に飢えている、そして今回は、これはヘビー級ロック状態で、食べることだけボウル(貧しい私を)戦うに行くとき

 

パート2:

私は毎日がブレークが非常に困難であり、コードを実行しビジー状態である、JVM(Java仮想マシン)内のスレッド、いのちなのです、人生のこの期間はやや退屈で、全世界がこれだけの人に思われます。

私は人間が呼ばれるいくつかの特別な場所にコードを書くことを聞いたクリティカル領域彼らはJVMのボスが実装に一つだけのスレッドを可能にすると同時に、非常に魔法あり、このようなコードの変更の同期方法やブロックなど、。

実際には、ボスはロックをつかむ、ロックを設定し、ロックを解除するために誰かを待って、実行、またはのみブロックすることができます。

ボスはブロッキングが働いて、そして正直にライン上で待機していない、と述べました。

しかし、これと他の良いものがまだあります!私はすぐに一度ブロックしましょう。

しかし、上司は言った:私が持っていたすべての時間は、オペレーティングシステムが扱うロックを設定する」と何をミューテックス(mutexを)維持するために彼に尋ねたカーネルにあるもの、彼はあなたに、スイッチを遮断するこれらのスレッドを運ぶために持っていた、これは合計です莫大なコストああ、これらのロック以下より良いです。 "

私の運がよくないですが、私はどのように実行されるか多くのコードがわからない、関数呼び出しの回数、一度もクリティカルセクションが遭遇したことはありません!

また、可能なこれらのプログラムのほとんどは問題なく実行されているどのように多くのスレッドステートレス、であることを、私は、おそらく偶然プログラマをプログラミングするときは、同時マルチスレッド考慮していないと思います。

私はそれを実装していたので、私は、コードの変更の同期ブロックが最後に出現することを見つけるために、励起された何日か分かりません。

アカウントアカウント= ...

同期(アカウント){

...コードのクリティカルセクション...

}

バイアスされたロック

私は完全に別のスレッドが、その後、私はブロックすることができ、残りの部分をブロックに入っていると予想しました。

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

可是老大根本没有去找操作系统, 只是看了看这个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万+

おすすめ

転載: blog.csdn.net/z69183787/article/details/104495882