Java Concurrencyプログラミングを学ぶには、java.util.concurrentパッケージについて学ぶ必要があります。 ReentrantLock、CountDownLatch、CyclicBarrier、Semaphoreなど、このパッケージの下でよく使用する多くの並行性ツールクラスがあります。これらのクラスの基礎となる実装はすべて、このクラスの重要性を示しています。そのため、Java Concurrencyシリーズでは、最初にAbstractqueuedsynchronizerクラスを分析しました。このクラスはより重要であり、コードは比較的長いため、可能な限り徹底的に分析するために、4つの記事を使用して、このクラスを比較的完全に紹介することにしました。この記事は、読者にこのカテゴリの予備的な理解を与えるための要約の紹介です。ナレーションを簡単にするために、一部の場所ではAQを使用して将来このクラスを表現します。
1. Abstractueuedsynchronizerクラスは何ですか?
多くの読者がReentrantLockを使用していると信じていますが、抽象的なシンクロナイザーの存在を知りません。実際、ReentrantLockは内部クラスの同期を実装します。すべてのロックメカニズムの実装は、同期内部クラスに依存しています。また、ReentrantLockの実装はAbstractqueuedSynchronizerクラスに依存すると言えます。同様に、CountDownLatch、CyclicBarrier、およびSemaphoreクラスも同じ方法を使用して、独自のロックの制御を実装しています。 Abstractqueuedsynchronizerがこれらのクラスの基礎であることがわかります。それでは、これらすべてのクラスがそれに依存するように、AQ内に正確に実装されるものは何ですか? AQSはこれらのクラスにインフラストラクチャを提供すると言えます。つまり、パスワードロックを提供します。これらのクラスにパスワードロックがあると、パスワードロックのパスワードを自分で設定できます。さらに、AQSはキューエリアとスレッドインストラクターも提供します。スレッドは原始的な野b人のようなものであることを知っています。彼らは礼儀正しくする方法を知りません。彼らは急いでいるだけなので、あなたはそれを段階的に教える必要があります、それがキューにする必要があるとき、どこでキューにするか、キューイングの前に何をすべきか、そしてキューイング後に何をすべきかを伝えなければなりません。これらの教育作業はすべて、あなたのためにAQによって完了します。それから教育を受けたスレッドは非常に文明的で礼儀正しく、原始的な野bar人ではなくなりました。したがって、将来的には、これらの文明化されたスレッドにのみ対処する必要があります。元のスレッドとの連絡が多すぎることはありません!
2.なぜAbstractqueuedSynchronizerがパスワードロックを提供するのですか?
//同期のヘッドノードキュープライベート一時的な揮発性ノードヘッド。 //同期のテールノードプライベート一時的な揮発性ノードテール; //プライベート揮発性int状態; //同期状態保護された最終的なintState(){return State;} //同期状態保護された最終voidセットステート(int newstate){state = newstate;} // set synchronization intectected protected protected protected setected setected protected protected protected protected setecte {unsafe.compareandswapintを返す(this、stateoffset、equient、update);}上記のコードには、AQのすべてのメンバー変数がリストされています。 AQには3つのメンバー変数、つまり同期キューヘッドノードリファレンス、同期キューテールノード参照、同期状態の3つのメンバー変数のみがあることがわかります。 3つのメンバー変数はすべて、揮発性キーワードで変更されていることに注意してください。これにより、複数のスレッドがメモリ可視であることが保証されます。クラス全体の中核は、この同期状態です。同期状態は、実際にはINTタイプの変数であることがわかります。この同期状態をパスワードロックと見なすことができます。また、部屋からロックされたパスワードロックでもあります。状態の特定の値は、パスワードロックの開閉を制御するパスワードと同等です。もちろん、このロックのパスワードは各サブクラスによって決定されます。たとえば、ReentrantLockでは、状態は0がロックが開いていることを意味し、状態は0を超えることを意味し、ロックがロックされていることを意味し、セマフォでは0を超える状態はロックが開いていることを意味し、状態は0がロックがロックされていることを意味します。
3。抽象的な症状のキューエリアはどのように実装されていますか?
実際には、abstractqueuedsynchronizer内には2つのキューイングエリアがあり、1つは同期キューで、もう1つは条件付きキューです。上記の図からわかるように、複数の条件キューがある場合がありますが、同期キューは1つだけです。同期キューのノードは、それぞれフロントノードとバックノードへの参照を保持しますが、条件付きキューのノードには後継ノードへの参照が1つしかありません。図では、tはスレッドを表します。各ノードにはスレッドが含まれています。スレッドがロックの取得に失敗した後、最初に同期キューに入り、キューに入ります。条件付きキューを入力する場合は、スレッドがロックを保持する必要があります。次に、キュー内の各ノードの構造を見てみましょう。
//同期キューのノードは、静的な最終クラスノード{静的最終ノード共有= new Node();です。 //現在のスレッドは、共有モードのロックを保持します。 //現在のスレッドは、ロックを排他モードで保持しますstatic final int canceled = 1; //現在のノードは、ロック静的最終int信号= -1をキャンセルしました。 //後継ノードのスレッドは、静的最終int条件= -2を実行する必要があります。 //現在のノードは、条件付きキューでキューに掲載されています。 //後続のノードは、ロック揮発性int waitstatusを直接取得できます。 //現在のノード揮発性ノードの待機状態を示します。 //次に同期キューの揮発性ノードの前方ノードを示します。 //同期キューの揮発性スレッドで後継ノードを示します。 //現在のノードが保持しているスレッドは、NextWaiterのノードを指します。 //条件付きキューの後継ノードを示します//は共有モードの最終的なブールisshared()の現在のノード状態です(){nextwaiter == shared; } //現在のノード最終ノード前身()の前方ノードを返しますnullpointerexception {node p = prev; if(p == null){新しいnullpointerexception(); } else {return p; }} // constructor 1 node(){} // constructor 2、このコンストラクターはデフォルトのノード(スレッドスレッド、ノードモード)で使用されます。 this.thread = thread; } //コンストラクター3、ノード(スレッドスレッド、int waitstatus)のみが条件キュー{this.waitstatus = waitstatus; this.thread = thread; }}ノードは、同期キューと条件付きキューのノードを表します。それは抽象的なabseuedsynchronizerの内部クラスです。ノードには、保持モード、待機状態、プレシーケンス、後継者の同期キュー、条件付きキューの後継リファレンスなど、多くの属性があります。同期キューと条件キューはキューエリアと見なすことができます。各ノードは、キューエリアの座席と見なされ、糸はキューゲストと見なされます。ゲストが最初に来ると、彼らはドアをノックして、ロックが開いているかどうかを確認します。ロックが開かれていない場合は、キューエリアに移動してナンバープレートを集め、ロックを保持する方法を宣言し、最後にキューの最後にキューアップします。
4排他的モードと共有モードを理解する方法は?
前述のように、各ゲストはキューイングの前にナンバープレートを受け取り、ロックを所有したいと宣言します。ロックを所有する方法は、排他的モードと共有モードに分割されます。では、排他的モードと共有モードをどのように理解していますか?私は本当に良い類推を見つけることができません。あなたは公共のトイレを考えることができます。排他的なモードを持つ人はより駆け出しです。私はどちらも入りません。私が入ったとき、私は他の人に入ることを許さない。私は一人でトイレ全体を占領します。共有モードの人々はそれほど特別ではありません。トイレがすでに使用可能であることがわかったとき、それがそれ自体に来るかどうかはカウントされません。彼らはまた、一緒にそれを使用することを気にするかどうかの背後にいる人々に熱心に尋ねなければなりません。後ろの人々が一緒に使用することを気にしない場合、列を並べる必要はありません。誰もが一緒に行くでしょう。もちろん、彼らの背後にいる人々が気にするなら、彼らは列にとどまり、キューイングを続けなければなりません。
5ノードの待機状態を理解する方法は?
また、各ノードには待機状態があり、これはキャンセル、信号、条件、伝播の4つの状態に分かれています。この待機状態は、座席の隣にぶら下がっている標識と見なすことができ、現在の座席の人の待機状態を特定します。このブランドのステータスは、自分で変更するだけでなく、他のブランドも変更できます。たとえば、このスレッドが既にキュー中にあきらめることを計画している場合、シートにサインを設定してキャンセルし、他の人がそれを見るとキューからそれをクリアすることができます。別の状況は、糸が座席で眠りにつくと、眠りにくくなることを恐れているため、QUEUEを離れる前に誰もが座席に戻るため、正面の位置のサインを変更することが恐れていることです。サインのステータスが信号であることがわかった場合、次の人を目覚めさせます。フロントポジションのブランドが信号であることを確認することによってのみ、現在のスレッドは平和に眠ります。条件ステータスは、スレッドが条件付きキューでキューにキューになっていることを示します。伝播ステータスは、後続のスレッドがロックを直接取得することを思い出させます。このステータスは共有モードでのみ使用され、共有モードについて個別に話すときに後で説明します。
6.ノードが同期キューに入ると、どのような操作が実行されますか?
// node enqueue操作、前のノードプライベートノードENQ(最終ノードノード)に戻ります((;;){//同期キューノードT =テールのテールノードへの参照を取得します。 //テールノードが空の場合、(t == null){//同期キューを初期化する場合、同期キューが初期化されていないことを意味します。 }} else {// 1。現在のテールノードnode.prev = t;を指します。 // 2。現在のノードをテールノードに設定しますif(compareandsettail(t、node)){// 3。古いテールノードの後継者を新しいテールノードt.next = nodeに向けます。 // forループの唯一の出口はtを返します。 }}}}Enqueue操作はデッドループを使用していることに注意してください。同期キューのテールにノードが正常に追加された場合にのみ、返されます。結果は、同期キューの元のテールノードです。次の図は、操作プロセス全体を示しています。
読者は、テールノードを追加する順序に注意を払う必要があります。テールノードは、テールノードを指す3つのステップに分割され、CASはテールノードを変更し、古いテールノードの後継者を現在のノードに向けます。同時環境では、これらの3つのステップが完了することを保証できない場合があります。したがって、非キャンセル状態でノードを見つけるために、同期キュー内のすべてのキャンセルされたノードをクリアする際に、それは正面から背面から前後に通過するのではなく、前後に通過します。また、各ノードがキューに入ると、その待機状態は0です。後続のノードのスレッドを一時停止する必要がある場合のみ、前のノードの待機状態が信号に変更されます。
注:上記の分析はすべてJDK1.7に基づいており、異なるバージョン間に違いがあります。読者は注意を払う必要があります。
上記はこの記事のすべての内容です。みんなの学習に役立つことを願っています。誰もがwulin.comをもっとサポートすることを願っています。