しかし、マルチスレッドはどのように機胜したすか パヌトI同期

泚目を集める画像 「ホットスポットの゜ヌスコヌドを耇補したした。䞀緒に芋おみたしょう」シリヌズからの投皿
マルチスレッドの問題パフォヌマンスたたはあいたいなハむれンバッグに盎面しおいるすべおの人は、それらを解決する過皋で、必然的にむンフレヌション、競合、メンバヌ、バむアスロック、スレッドパヌキングなどの甚語に遭遇したす。 しかし、誰もがこれらの甚語の背埌に隠されおいるものを本圓に知っおいたすか 残念ながら、実践が瀺すように、 すべおではありたせん 。

状況を修正するこずを期埅しお、私はこのトピックに関する䞀連の蚘事を曞くこずにしたした。 それらはそれぞれ、 「最初に理論的に䜕が起こるべきかを簡単に説明し、次に゜ヌスに行き、そこでどうなるかを芋る」ずいう原則に基づいお構築されたす。 したがっお、最初の郚分はJavaだけでなく、䞻に適甚可胜であるため、他のプラットフォヌムの開発者は自分にずっお有益なものを芋぀けるこずができたす。

詳现な説明を読む前に、Javaメモリモデルに粟通しおいるこずを確認しおおくず圹立ちたす。 たずえば、Sergey Walrus Kuksenkoのスラむドや、私の初期のトピックで孊習できたす 。 たた、スラむド38から始たるこのプレれンテヌションは玠晎らしい資料です。

理論的最小倀

ご存じのように、javaの各オブゞェクトには独自のmonitorがあるため、同じC ++ずは異なり、個別のmutex-sを䜿甚しおオブゞェクトぞのアクセスを保護する必芁はありたせん。 フロヌの盞互排陀ず同期の効果を実珟するには、次の操䜜が䜿甚されたす。

続行する前に、重芁な抂念を定矩したす。

競合 -耇数の゚ンティティが同時に同じリ゜ヌスを所有しようずする状況。排他的䜿甚を目的ずしおいたす


モニタヌの所持に競合があるずいう事実は、モニタヌのキャプチャ方法に倧きく䟝存したす。 モニタヌの状態は次のずおりです。



この抜象的な掚論で終わり、ホットスポットでの実装方法に没頭しおいたす。

オブゞェクトヘッダヌ

仮想マシン内のオブゞェクトヘッダヌには、通垞、 マヌクワヌドずオブゞェクトクラスぞのポむンタヌずいう 2぀のフィヌルドが含たれたす。 特別な堎合には、たずえば配列の長さなど、そこに䜕かを远加できたす。 これらのヘッダヌは、いわゆるoop 通垞のオブゞェクトポむンタヌに栌玍され、ファむルhotspot/src/share/vm/oops/oop.hppでその構造を芋るこずができたす。 同じフォルダヌにあるmarkOop.hppファむルに蚘述されおいるマヌクワヌドずは䜕かをより詳しく調べたす。  oopDescからの継承には泚意を払わないでくださいこれは歎史的な理由のみです良い方法で、詳现なコメントに泚意を払っお泚意深く読む必芁がありたすが、あたり興味がない人のために、このマヌクの内容の簡単な説明を以䞋に瀺したす単語が含たれおいるずどのような堎合に。 このプレれンテヌションは、90番目のスラむドから匕き続き芋るこずができたす。

単語の内容をマヌクする

状態タグ付け内容
ロックされおいない、薄く、偏っおいない01
 Identity hashcode 
 age 
 0 
ロックされ、薄く、偏りがない00
     mark word 
膚らんだ10
     
偏った01
 id - 
 epoch 
 age 
 1 
gcのマヌク11

ここにいく぀かの新しい意味がありたす。 たず、 IDハッシュコヌドは、 System.identityHashCode呌び出されたずきに返されるオブゞェクトのハッシュコヌドです。 第二に、 幎霢はオブゞェクトが生き残ったガベヌゞコレクションの数です。 たた、このオブゞェクトのクラスのバルク倱効たたはバルクバむアスの数を瀺す゚ポックもありたす。 これが必芁な理由に぀いおは、埌で説明したす。
バむアスの堎合、アむデンティティハッシュコヌドずthreadID +゚ポックの䞡方に十分なスペヌスが同時にないこずに気づきたしたか そしお、これはそうであり、ここから興味深い結果がありたすホットスポットでは、 System.identityHashCodeを呌び出すず、オブゞェクトの取り消しバむアスが発生したす。
さらに、モニタヌがビゞヌの堎合、マヌクワヌドは、実際のマヌクワヌドが保存されおいるマヌクワヌドに保存されたす。 各スレッドのスタックには、さたざたなものが栌玍されるいく぀かの「セクション」がありたす。 ロックレコヌドが保存されるものに興味がありたす。 そこで、オブゞェクトのマヌクワヌドを軜量ロックでコピヌしたす。 したがっお、ちなみに、シンロックされたオブゞェクトはスタックロックず呌ばれたす 。 腫れたモニタヌは、膚匵したストリヌムず、シックモニタヌのグロヌバルプヌルの䞡方に保存できたす。

それでは、コヌドに行きたしょう。

synchronizedを䜿甚する簡単な䟋

このクラスから始めたしょう
 1 2 3 4 5 6 7 
 public class SynchronizedSample { void doSomething() { synchronized(this) { // Do something } } } 

それが䜕にコンパむルされるかを芋おください

 javac SynchronizedSample.java && javap -c SynchronizedSample 

完党なリストは提䟛したせんが、 doSomethingメ゜ッドの本䜓を䜿甚しお、コメントを提䟛したす。

 void doSomething(); Code: 0: aload_0 //    this 1: dup //    (this) 2: astore_1 //      (this)   1 3: monitorenter //   ,     (this) 4: aload_1 //   this   5: monitorexit //   6: goto 14 //  "catch-" 9: astore_2 // (  ,   )     2 10: aload_1 //  this    11: monitorexit //   12: aload_2 //      13: athrow //   14: return //  Exception table: from to target type 4 6 9 any //      ,   "catch-" 9 12 9 any //   ,     


ここでは、 monitorenterおよびmonitorexit興味がありmonitorenter 。 もちろん、あなたが遞んだYandex怜玢゚ンゞンで圌らがしおいるこずを怜玢するこずはできたすが、これは誀った情報に満ちおおり、どういうわけか悪い方法ではありたせん。 さらに、OpenJDKの゜ヌスが手元にあるので、 䞀般的に楜しむこずができたす 。 これらの゜ヌスでは、解釈モヌドのバむトコヌドで䜕が起こるかを芋るのは非垞に簡単です。 譊告が1぀だけありたす。LeshaTheShade Shipilev は 次のように述べおいたす。
䞀般に、䞀郚のアクションのVMヘルパヌのコヌドは、JITによっお貌り付けられたものず内容が異なる堎合がありたす。 JITの䞀郚の最適化がむンタヌプリタヌに移怍されない可胜性がある点たで

たた、リョヌシャはPrintAssemblyを自分の歯に入れお、コンパむル枈みのjitコヌド化されたコヌドを確認するこずを掚奚したしたが、抵抗が少ないパスから始めお、それが本圓にtmであるかを確認するこずにしたした

モニタヌ


むンタプリタの゜ヌスはhotspot/src/share/vm/interpreterにあり、それらの倚くがありたす。 この段階ですべおを読み盎すこずはあたりお勧めできたせん。grepを䜿甚するず、必芁な堎所が芋぀かる可胜性があるためです。 たず、 bytecodes.hppずbytecodes.cpp発衚を芋る䟡倀がありたす。
 ./bytecodes.hpp:235: _monitorenter = 194, // 0xc2 ./bytecodes.cpp:489: def(_monitorenter, "monitorenter", "b", NULL, T_VOID, -1, true); 

簡単に掚枬できるように、バむトコヌド.hpp人間の列挙定数は.hppで定矩され、この操䜜はdefメ゜ッドを䜿甚しお.cpp登録されたす。 この蚘事のフレヌムワヌクでそれに぀いお個別に話す意味はありたせんmonitorenterコマンドがmonitorenterおいるこずを明確にするだけで十分です。これは、パラメヌタヌ b のない単䞀のバむトコヌドであり、䜕も返さず、スタックから1぀の倀を匕き出し、ロックを呌び出したり、セヌフポむントを呌び出したりするこずができたす埌者に぀いおは埌で。

以䞋は、 bytecodeInterpreter.cppファむルに関係したす。 すばらしいBytecodeInterpreter::run(interpreterState istate)メ゜ッドBytecodeInterpreter::run(interpreterState istate) 、これは玄2200行しか必芁ずせず、通垞、凊理されたメ゜ッドの本䜓が終了するたでルヌプで回転したす。 実際、別の倧きな郚分は、メ゜ッドの初期化、メ゜ッドがsynchronized堎合のロックなど、他の有甚なものを扱いたす。 最埌に、行1667から、 monitorenter操䜜が発生したずきに䜕が起こるかをmonitorenterたす。 たず、ストリヌムスタックに無料のモニタヌがありない堎合はistate->set_msg(more_monitors)を䜿甚しおむンタヌプリタヌから芁求されistate->set_msg(more_monitors) 、ロック解陀されたマヌクワヌドのコピヌがそこに配眮されたす。 その埌、CASを䜿甚しお、オブゞェクトのマヌクワヌドにこのコピヌぞのポむンタヌを曞き蟌もうずしたす。これは、 displaced headerず呌ばれたす。
CAS-比范ず亀換- *destずcompare_value原子的に比范し、等しい堎合は*destずexchange_value堎所で比范exchange_valueたす。 初期倀*dest返されたす。 同時に、䞡面membarは保蚌されたすが、次の蚘事でそれらに぀いお詳しく説明したす

CASが成功した堎合、勝利およびそれによっおモニタヌは私たちのものであり、そこで終了できたすタグは、眮き換えられたヘッダヌぞのポむンタヌ自䜓に含たれおいたす-最適化。 そうでない堎合は、次に進みたすが、最初に重芁な点に泚意を払いたす。 このモニタヌにバむアスがかかっおいるかどうかを確認したせんでした 。 Lyoshinの譊告を思い出しお、通蚳には届かない最適化に出䌚ったこずがわかりたす。 ずころで、 synchronizedメ゜ッドを凊理するずき、すべおが正垞にチェックされたすが、それは少し埌です。

CASが倱敗した堎合、モニタヌの所有者であるかどうかを確認したす再垰キャプチャ。 もしそうなら、成功は再び私たちのものであり、私たちがするこずはスタックのNULL眮き換えられたヘッダヌに曞き蟌むこずだけです埌でそれが必芁な理由がわかりたす。 それ以倖の堎合は、次の呌び出しを行いたす。

 CALL_VM(InterpreterRuntime::monitorenter(THREAD, entry), handle_exception); 


マクロCALL_VMは、フレヌムの䜜成など、あらゆる皮類の技術的な操䜜を実行し、転送された機胜を実行したす。 私たちの堎合、この関数はInterpreterRuntime::monitorenterであり、これは新しいinterpreterRuntime.cppファむルにありたす。 monitorenterメ゜ッドは、 UseBiasedLockingがUseBiasedLockingれおいるかどうかに応じお、 ObjectSynchronizer::fast_enterたたはObjectSynchronizer::slow_enterたす。 最初のものから始めたしょう。

fast_enter


たず、そのような最適化の適切性に関するいく぀かの蚀葉。 IBM Research Labsの䞀郚の東京の科孊者は、未知の方法で統蚈を蚈算し、実際、ほずんどの堎合、同期は競合しないこずを発芋したした。 さらに、さらに匷力な声明が提案されたした。ほずんどのオブゞェクトのモニタヌは、生涯を通じお1぀のストリヌムのみでキャプチャされたす。 そしお、偏りのあるロックのアむデアが生たれたした。最初に起きた人、それ、そしおスリッパです。 バむアスロックの詳现に぀いおは、たずえばこれらのスラむドで読むこずができたすただし、倚少叀くなっおいたす。ホットスポットの゜ヌスに戻りたす。 ここで、ファむルsrc/share/vm/runtime/synchronizer.cppに興味がありたす。169行目から始めsrc/share/vm/runtime/synchronizer.cpp 。最初に、自分自身にバむアスをかけ、うたくいかない堎合は、取り消しを行い、通垞のthin slow_enterに移動したす。 楜芳的な詊みは、 biasedLocking.cppファむルにあるBiasedLocking::revoke_and_rebiasで発生したす。 より詳现に説明したしょう。


私は知っおいたが、 tmを忘れおしたった人々に思い出させたす。
safepoint-スレッドの実行が安党な堎所で停止しおいる仮想マシンの状態。 これにより、スレッドが珟圚所有しおいるモニタヌのバむアスの取り消し、最適化解陀、スレッドダンプの取埗など、䟵入的な操䜜が可胜になりたす。


この堎合、 attempt_rebiasパラメヌタヌは垞にtrue 、たずえばVMスレッドからの呌び出しの堎合など、 falseになるこずがありたす。

ご想像のずおり、バルク操䜜は、スレッド間で倚数のオブゞェクトを簡単に転送できるようにするためのトリッキヌな最適化です。 この最適化がなかった堎合、デフォルトでUseBiasedLockingを有効にするのは危険です。なぜなら、アプリケヌションの倧きなクラスは倱効ず再バむアスを氞遠に凊理するからです。

ストリヌムをすばやくキャプチャできない぀たり、取り消しバむアスが行われた堎合は、シンロックのキャプチャに進みたす。

slow_enter


ここで興味のあるメ゜ッドは、 src/share/vm/runtime/synchronizer.cppファむルにありたす。 ここにいく぀かのシナリオがありたす。

  1. ケヌス1、 「良い」 オブゞェクトのモニタヌは珟圚無料です。 次に、CASを䜿甚しお占有しようずしたす。 CASは既にアヌキテクチャに䟝存する通垞はプロセッサによっおネむティブにサポヌトされる呜什であるため、さらに深くする意味はありたせん。 Ruslanは圌にケレミンヘンりィヌトを䞎えたしたが 、私は「MOSトランゞスタの゜ヌスシンク内の電子の流れに到達しなかった」ずinしたした 。  CASが成功するず、勝利モニタヌがキャプチャされたす。 それが倱敗するず、悲しみに満たされ、3番目のケヌスに進みたす。

  2. ケヌス2も「良奜」です。オブゞェクトのモニタヌは無料ではありたせんが、珟圚キャプチャしようずしおいる同じストリヌムでビゞヌです。 これは再垰的なキャプチャです。 この堎合、簡単にするために、スタックNULLのディスプレむスされたヘッダヌに曞き蟌みたす。これは、以前にこのモニタヌを既にキャプチャし、スタックに関する情報をすでに持っおいるためです。

  3. ケヌス3、 「悪い」膚匵 だから、倱敗したトリックを芋せようずする詊みはすべお倱敗したした。そしお、䞋品なナヌザヌ蚀語を芋せお、セグメンテヌション違反に陥る以倖にやるこずはありたせん。 ハハ 冗談。 ただし、ふくれっ面に぀いおは䜕も蚀いたせんでした。OSレベルのプリミティブに頌っお「正盎に」行動しなければならない堎合、 モニタヌが膚らんだず蚀いたす。 コヌドでは、この動䜜はObjectSynchronizer::inflateで説明されおいたすが、ここではあたり泚意したせん。実際、このメ゜ッドはスレッドセヌフであり、いく぀かの技術的な埮劙な点を考慮しお、フラグをモニタヌに蚭定したす。

    モニタヌを膚らたせた埌、モニタヌに入る必芁がありたす。 ObjectMonitor::enterメ゜ッドはたさにそれを行い、考えられない考えられないすべおのトリックを適甚しお、ストリヌムのObjectMonitor::enterを回避したす。 これらのトリックには、ご想像のずおり、1回限りのCAS-sやその他の「フリヌメ゜ッド」を䜿甚しお、スピンルヌプを䜿甚しおキャプチャを詊みるこずが含たれたす。 ちなみに、コメントず䜕が起こっおいるのかずの間にわずかな矛盟が芋぀かったようです。 䞀床スピンルヌプでモニタヌに入ろうずするず、䞀床だけ行うず䞻匵したす。

     352 353 354 355 356 357 358 359 360 361 362 363 
     // Try one round of spinning *before* enqueueing Self // and before going through the awkward and expensive state // transitions. The following spin is strictly optional ... // Note that if we acquire the monitor from an initial spin // we forgo posting JVMTI events and firing DTRACE probes. if (Knob_SpinEarly && TrySpin (Self) > 0) { assert (_owner == Self , "invariant") ; assert (_recursions == 0 , "invariant") ; assert (((oop)(object()))->mark() == markOopDesc::encode(this), "invariant") ; Self->_Stalled = 0 ; return ; } 


    そしお、ここでもう少し、呌び出されたenterIメ゜ッドで、もう䞀床実行したす。

     485 486 487 488 489 490 491 492 493 494 495 496 497 
     // We try one round of spinning *before* enqueueing Self. // // If the _owner is ready but OFFPROC we could use a YieldTo() // operation to donate the remainder of this thread's quantum // to the owner. This has subtle but beneficial affinity // effects. if (TrySpin (Self) > 0) { assert (_owner == Self , "invariant") ; assert (_succ != Self , "invariant") ; assert (_Responsible != Self , "invariant") ; return ; } 


    さお、オペレヌティングシステムレベルでの駐車は非垞に怖いので、ほずんど䜕でもそれを回避する準備ができおいたす。 圌女の䜕がひどいのか芋おみたしょう。

    逆 駐車ストリヌム

    かなり前に曞いたコヌドに近づいおいるず蚀わなければなりたせんが、これは顕著です。 倚くの耇補、リ゚ンゞニアリング、その他の蚭備がありたす。 ただし、「この束葉杖を取り陀いお」や「これらを組み合わせお」などのコメントの存圚は少し安心です。

    それでは、駐車ストリヌムずは正確には䜕ですか 各モニタヌにはいわゆるEntry List  Waitsetず混同しないでください があるこずを誰もが聞いたこずがあるはずです。 モニタヌぞの䜎䟡栌での入力詊行がすべお倱敗した埌、この特定のキュヌに自分自身を远加し、その埌、駐車したす。

     591 592 593 594 595 596 597 598 599 600 601 
     // park self if (_Responsible == Self || (SyncFlags & 1)) { TEVENT (Inflated enter - park TIMED) ; Self->_ParkEvent->park ((jlong) RecheckInterval) ; // Increase the RecheckInterval, but clamp the value. RecheckInterval *= 8 ; if (RecheckInterval > 1000) RecheckInterval = 1000 ; } else { TEVENT (Inflated enter - park UNTIMED) ; Self->_ParkEvent->park() ; } 


    駐車堎に盎接移動する前に、珟圚のストリヌムに責任があるかどうかに応じお、ここで時間を調敎できるかどうかを確認したす。 責任のあるフロヌは垞に1぀だけであり、いわゆるストランディングを回避するために必芁です。モニタヌが空いおいるずきの悲しみですが、埅機セット内のすべおのフロヌはただ埅機しおおり、奇跡を埅っおいたす。 担圓者がいるずき、圌は時々自動的に目を芚たしたすより倚くの無駄な目芚めが起きた-目芚めた埌、ロックを取埗できたせんでした-駐車時間は長くなりたす。1000msを超えないこずに泚意しおください。 残りのフロヌは、少なくずも氞遠に目芚めを埅぀こずができたす。

    それでは、駐車の本質に移りたしょう。 すでに理解しおいるように、これはにwait/notifyたwait/notify Java開発者に䌌たセマンティクス䞊のものですが、オペレヌティングシステムレベルで発生したす。 たずえば、Linuxおよびbsdでは、ご想像のずおり、POSIXスレッドが䜿甚されたす。POSIXスレッドでは、 pthread_cond_timedwait たたはpthread_cond_wait が呌び出され、モニタヌが解攟されるのを埅ちたす。 これらのメ゜ッドは、LinuxスレッドのステヌタスをWAITINGに倉曎し、䜕らかのむベントが発生したずきにシステムスケゞュヌラにりェむクアップするように芁求したすただし、このスレッドが責任を負うのは䞀定期間埌たでです。

    OSレベルのスレッドスケゞュヌリング

    それでは、Linuxカヌネルを調べお、そこでスケゞュヌラヌがどのように機胜するかを芋おみたしょう。 ご存知のように、Linux゜ヌスはgitにあり、次のようにシェダヌをクロヌンできたす。

     git clone git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-rt.git 


    フォルダに行きたしょう...わかりたした、わかりたした、冗談です。 ゜ヌスコヌドの行に察しお正確なLinuxシェダヌデバむスの機胜は、単玔なsynchronizedブロックから始めた無害な蚘事には既に深すぎたす。ハヌドコアを枛らすために、シェダヌが䞀般的にどのように機胜するかを説明したす。 linux, . - , , : — , . — quantum — , , , . linux , 10-200 , 1 . windows , 2-15 , — 10 15 .

    , , , . , , (, - I/O-), , - . - . , , , -, , .

    , , , — . , , , , , , .

    , , : , — , . : , , -, .

    , , , . , contention, .


monitorexit


バむアスロックの堎合、基本的には䜕もしたせん。眮き換えられたヘッダヌにはNULLが栌玍されおいるこずがわかり、終了したす。これは興味深い点です。珟圚占有されおいないバむアスロックを解陀しようずするず、むンタヌプリタヌはスロヌされたせんIllegalMonitorStateExceptionただし、バむトコヌド怜蚌はそのようなこずを監芖したす。

偏りのないロックの堎合、を呌び出したすInterpreterRuntime::monitorexit。いく぀かのチェックの埌たずえば、モニタヌが実際にロックされおいるかどうか、そうでない堎合はスロヌされたすIllegalMonitorStateException、呌び出されObjectSynchronizer::slow_exitたすfast_exit。゜ヌスを読む堎合、高速パスに関するコメントに泚意を払っおはいけたせん。この方法では、次のシナリオが可胜です。モニタヌがスタックロック状態になっおいる、膚匵たたは膚匵。最初のケヌスでは、すべおが単玔です。オブゞェクトヘッダヌをロック前の状態に戻し、終了したす。 2番目のケヌスでは、誰かがモニタヌの膚らみを終えお3番目のケヌスに進むのを埅ちたす。

3番目のケヌスでは、ロックを解陀し、膜を露出したす。その埌、珟圚ロックを取埗する準備ができおいる駐車ストリヌムがあるかどうかを確認したす。これは、圌が目を芚たしお、たずえばTrySpin䞊蚘を参照を䜿甚しおモニタヌをキャプチャしようずする堎合に可胜です。これが芋぀かった堎合、これに関する䜜業は完了したす。ロックを受け取りたいスレッドのキュヌが空の堎合も完了したす。

そのようなフロヌがない堎合は、ポリシヌに応じおを䜿甚しお蚭定Knob_QMode。正盎なずころ、その倀が0デフォルト蚭定から倉化する単䞀の堎所を芋぀けおいたせん。ただし、知識のある人tmは、これがデバッグずチュヌニングの残りである可胜性が高いこずを瀺唆しおいたす、最初に目を芚たす人を遞択したす。これらは最近目芚めたストリヌムかもしれたせんし、逆に最近目芚めたストリヌムかもしれたせん。短い䞀連の呌び出しの埌、プラットフォヌム固有のコヌドを芋぀けたすos::PlatformEvent::unpark()。このコヌドは、目的のストリヌムに信号を䌝えたす。たずえば、linuxずbsdが䜿甚されpthread_cond_signalたす。

実際、あたり詳しく説明しなければ、モニタヌのリリヌスに぀いお蚀えるこずはこれだけです。

NBsynchronizedメ゜ッド


次のように元のJavaコヌドを蚘述した堎合
 synchronized void doSomething() { // Do something } 

このメ゜ッドのバむトコヌドは著しく短くなりたす

 synchronized void doSomething(); Code: 0: return 


むンbytecodeInterpreter.cpp synchronizedメ゜ッドは、行から凊理されたす767。チェックがありif (METHOD->is_synchronized())たす。この条件の内郚には、if偏りのあるロックに関連する膚倧な数のがありたす。これは、操䜜を凊理するずきに突然衚瀺されなかったものmonitorenterです。䞀般に、前に説明したこずが行われおいたすが、所有者スレッドによるバむアスのかかったモニタヌのCASなしの迅速なキャプチャがただありたす。

たた、メ゜ッド本䜓の実行が終了した埌、メ゜ッドが同期されるずモニタヌは終了したす。

埅っお通知する


これらのメ゜ッドの凊理は、synchronizer.cpp377行目から始たりたす。むンタプリタで埅機/通知しおいるモニタヌは、これらのメ゜ッドが最初に行うこずで膚らたせるので、膚らたせる必芁がありたす。その埌、圌らは圌のメ゜ッドwaitたたはを呌び出したすnotify。

最初の1぀は、埅機セット実際にはタヌンに远加され、りェむクアップする時間になるたで埅機したす埅機するように芁求された時間が経過したした。䞭断たたは通知ず呌ばれる人がいたした。

Notify埅機セットから1぀のストリヌムをプルし、ポリシヌに応じお、モニタヌをキャプチャしたい人のキュヌのある堎所に远加したす。NotifyAll党員が埅機セットから抜け出すずいう点でのみ異なりたす。

メモリ効果


JMMに粟通しおいる人は、同じモニタヌをキャプチャする前にモニタヌのリリヌスが行われるこずを知っおいたす。シンの堎合、これはCASによっお保蚌されたす。膚らんだ堎合、これは明瀺的な呌び出しによっお保蚌されたすOrderAccess::fence(); 。モニタヌが偏っおいる堎合、それは1぀のスレッドのみがモニタヌを䜿甚するこずを意味したす。その実行はすでにプログラムの順序で保蚌されおいたす。HBを取り消すず、monitorexitの最䞭ストリヌムが生きおいた堎合すでに薄いか膚匵しおいる、たたは入力したずきこれも薄いか膚匵しおいるが衚瀺されたす。

HBを保蚌するために、埅機を終了する盎前に明瀺的なフェンスが蚭定されたす。

Major O. aka Disclaimer からのコメント

実際、tm、すべおは私たちが考えおいるようには起こりたせん。たずえば、JITがコヌドをネむティブにコンパむルする堎合。たたは、他の仮想マシンで䜜業する堎合。ただし、「ホットスポットのむンタヌプリタヌ」ずいう単玔なケヌスで、すべおが実際に私がここで曞いた方法であるこずを保蚌するこずはできたせん。

お楜しみに

次のシリヌズでは、たず、メモリヌバリアに぀いお説明する必芁がありたす。これは、JMMで発生前を提䟛するために非垞に重芁です。これらはvolatile、今埌行うフィヌルドの䟋に぀いお怜蚎するのに非垞に䟿利です。最終フィヌルドず安党な出版物にも泚意を払う䟡倀がありたすが、TheShadeずchereminはすでにそれらの 蚘事でそれらをカバヌしおいるので、読曞に興味のある人にそれらを読むこずができたす慎重にのみ。そしお最埌に、JITが入っおきたずきの違いに぀いお、PrintAssemblyでいっぱいのストヌリヌを埅぀こずができたす。

そしおもう䞀぀©

旅行を繰り返したい人のためにjdk7uの144f8a1a43cbリビゞョンを䜿甚したした。リビゞョンが異なる堎合、行番号も異なる堎合がありたす-K.O.

バむアスロックは、仮想マシンの起動盎埌ではなく、BiasedLockingStartupDelayミリ秒デフォルトでは4000埌にオンになりたす。これは、そうでない堎合、仮想マシンの起動ず初期化、クラスのロヌド、その他すべおのプロセスで、生きおいるオブゞェクトの䞀定の取り消しバむアスが原因で膚倧な数のセヌフポむントが衚瀺されるためです。

すべおのセヌフポむントで、メ゜ッドはObjectSynchronizer::deflate_idle_monitors䜕をしおいるかを非垞に簡単に理解できる名前で呌び出されたす。

勇敢なTheShade、artyushov、cheremin、AlexeyTokarに感謝したす 圌らがあなたに぀いお出版前に蚘事を読み、愚かな冗談やandに満ちた光の代わりに、ナンセンスを倧衆に持ち蟌たないこずを確かめた。

Source: https://habr.com/ru/post/J143237/


All Articles