最終的にはどのような並行プログラミングメモリモデル-Javaです

メモリモデル

これら三つの速度のバランスを取るコンピュータのCPU、メモリ、3間のIOの速度差、システムのパフォーマンスを向上させるために、で。

  • 増加バランスするCPUキャッシュとメモリの速度差。
  • オペレーティング・システムは、このようにCPUとI / Oデバイスとの間の速度差のバランスを取る、プロセス、スレッド、時分割多重CPUを増加させます。
  • コンパイラの最適化の命令実行順序、バッファは、より合理的な使用することができますように。

これらの3つのシステムの最適化は、ハードウェアの効率が大幅に改善されているが、彼らはまた、視認性、不可分性と秩序やその他の問題をもたらしました。メモリキャッシュベースのインタラクティブなCPUがうまくCPU速度やメモリの競合を持って解決したが、また、コンピュータシステムの複雑さを増加させ、新たな問題が導入されている:キャッシュコヒーレンス(キャッシュコヒーレンスを)。

各プロセッサは、メインメモリ領域の同じ部分に関連する複数のプロセッサ・コンピューティングタスクは、おそらく一貫性のないデータになりますと、複数のプロセッサが、その後、メインシステムメモリを共有し、独自のキャッシュがあまりにも排他持って誰にデータの対象は、問題となりました。一貫性の問題を解決するために、各プロセッサは、これらの契約の下で操作を読み書きするためのいくつかのプロトコルに従うことが必要です。だから、メモリモデルは、特定のオペレーティング契約に基づき、キャッシュ・コヒーレンシの問題を解決読んで、特定のメモリやキャッシュプロセスへの書き込みが抽象的であると理解することができます。

Javaのメモリモデル

JMM役割

Java仮想マシン仕様(Javaのメモリモデル、JMM)は、Javaメモリモデルを定義しようと、Javaプログラムは、同じ効果メモリアクセスを実現するために、さまざまなプラットフォームを実現することを可能にするために、メモリアクセスのハードウェアとオペレーティング・システムの違いを保護するために使用されますJavaプログラマは異なるプロセッサプラットフォームごとに異なるメモリモデルを無視して、できるように、唯一のJMMを心配する必要があります。

JMM抽象的構造

抽象構造図JMM

JMMプロセッサ・メモリ・モデルは、ビューの抽象的な点のアイデアへの描画、JMMは、キャッシュ、バッファを書き込み、レジスタおよび他のハードウェアおよびコンパイラの最適化をカバーし、スレッドとメインメモリとの間の抽象関係を定義します。図は、JMMの抽象の概略図です。

スレッド間通信におけるJMM

考慮すべき並行プログラミングにおける2つのコアの問題:どのようにスレッド(可視性と秩序)との間で通信するために、どのようにスレッド(原子)との間で同期します。同期制御するためのプログラムで異なるスレッド間で発生する動作の相対的な順序を指し、通信は、スレッド間の情報交換をする方法をいいます

JMMは、メインメモリに記憶されている(例えばフィールド、静的フィールドは、オブジェクト要素、等のアレイを構成する)すべての変数の手順を定め、その主な目的は、仮想マシン変数が格納されている両方から、変数のプログラムタイプを定義されたアクセスルールでありますメモリのような低レベルの詳細とメモリ変数種から除去されます。各スレッド間で独自のローカルメモリ、JMMメインメモリを制限することによって制御下糸通信プロトコルを有しています。スレッドBは、送信スレッドを与えるために、二つのスレッドA及びBが想定「ハロー」メッセージは、プロセスは、2つのスレッド図通信である。

図から分かるように、スレッドAは、スレッドBへのメッセージであると仮定され、それがなければなりませんステップ2:

  1. メインメモリにフラッシュメモリ更新メッセージで共有変数のローカル・コピーにスレッド
  2. 更新共有変数スレッドにメッセージを読むために、メインメモリを取るためにスレッドB

JMMの設計と実装

JMM関連のプロトコルより複雑な、我々は、コンパイラやJVMのエンジニアだけでなく、Javaのエンジニアから学ぶことができます。JMMを議論するだけのJavaのJavaエンジニアの観点から、この記事では、データの一貫性を確保するために、これらの協定によって制御されます。

JMMの実装では、ルールの前に、起こると、一連のキーワードを含む二つの部分に分けることができます。そのコアの目的は、コンパイラは、プロセッサ・プラットフォームは、一貫性のある動作を提供できることを保証することである、メモリに一貫性のある結果を示しました。具体的には、視認性を解決し、並びに原子の秩序化の問題が起こる前に、ルール及び揮発性、同期、最終的なキーワード、従ってメモリ内のデータの一貫性を確保します。

事前発生ルール

前起こるJMMの中核概念であり、事前発生二つの操作の間の実行順序を指定するために、両方の操作がスレッドであってもよく、それは、このように発生し、前JMMにより、スレッドでも異なっていてもよいです:メモリー関係は次のようにクロススレッド、JMMが定義されていることを保証するために、プログラマに可視性を提供します

  1. さらに、事前発生した場合の動作を操作する、第2の操作の操作の実行結果は、第2の動作前に実行の一次及び放電動作が分かるであろう。
  2. 2つの操作があっ起こる-前に関係が実行されることにより、特異的な配列を達成するためのJavaプラットフォームを指定しなければならないことを意味するものではありません、関係-の前に起こります。並べ替え後の結果は、によって結果と一致が起こる前に、関係が行われた場合、この並べ替えは違法ではない(すなわち、JMMはそのような並べ替えを可能にする、です)

スレッドB「V ==真」かどうかを確認、実行はライター()メソッドは、スレッドBは、リーダ()メソッドを実行したスレッドと仮定すると、サンプルコード以下、次に参照する変数xスレッドBはどのくらいですか?

class VolatileExample {
  int x = 0;
  volatile boolean v = false;
  public void writer() {
    x = 42;                 // 1
    v = true;               // 2
  }
  public void reader() {
    if (v == true) {        // 3
      // 这里 x 会是多少呢?  // 4
    }
  }
}

1.プログラムシーケンスルール

ルールのプログラムシーケンス(プログラム順ルール):スレッド内の各操作は、コードシーケンスに従って、先の書き込み動作のコードブックEDITORIALはバックで発生します。

2. volatile変数のルール

揮発性変数ルール(volatile変数ルール):最初の書き込み操作が読み取られたこの変数の面で発生した後、揮発性変数修飾のために得ました。「後ろに」時間の配列をいいます

3.転送ルール

転送ルール(推移):動作が先に発生した場合手順B、Bは先動作は、第1の動作において、AがCを発生し、その後、手順Cにおいて生じます

これらの項目への応答1,2,3-が起こる-前に、我々は要約を行うには、以下の事前発生である私たちは、揮発性の読み取りと書き込みに基づいてダイアグラムを構築します。

4.チェンロックルール

チューブロックルール(モニターロックルール):最初のロック解除操作をロックして操作した後、キーロックの顔に発生します。「後ろに」時間の配列をいいます

前の記事で同時実行の問題の源問題の我々は、この問題の原子を解決するために事前発生ルールを利用しようとすることが可能なカウンティング問題でスレッド切り替え結果に言及++同時実行性の問題を、数えます。

public class SafeCounter {
  private long count = 0L;
  public long get() {
    return cout;
  }
  public synchronized void addOne() {
    count++;
  }
}

コードは本当に解決する問題を解決することができますか?

4.スレッド開始規則

スレッド開始規則(スタートルールスレッド):Threadオブジェクト()メソッドは、このスレッドで最初に出現するすべての動きを開始します。

6.スレッドがルールを終了します

)このスレッドの検出で発生し、我々はThread.join()メソッド、Thread.isAlive(で終了することができますすべての操作は先にスレッドの終了のあるスレッドの実行かどうかを検出するために、他の手段の値を返します:スレッドがルール(スレッドの終了ルール)を終了します完了しました。

7.スレッドのブレークルール

スレッドは、(中断ルールスレッド)のルールを破る:スレッドを中断するために呼び出す()メソッドは、最初のイベントが発生し中断し、中断スレッドコード検出で発生した割り込みが発生した場合、Thread.interrupted()メソッドによって検出することができます。

8.オブジェクト確定ルール

ルールオブジェクト(ファイナライザルール)の終了:オブジェクト(コンストラクタが終了した)の初期化の完了は、最初にファイナライズ()メソッドで発生しました。

6について詳細に説明する前に起こる、前規則は、個以上の合計に並行プログラミングにおける唯一の共通のために著者を分割することができ、特定のコンテンツがhttp://gee.cs.oswego.edu/dl/jmm/cookbookを参照することができ.htmlを。JMMでは、私は、これらのルールの概念は理解することがより困難であると思います。結論することが起こり、前のルールは関係の視認性を重視し、イベントAが発生し、前にBを、Bは、イベントのためのイベントを意味しかかわらず、イベントA及びBはスレッドで発生するかどうかの、表示されています。

volatileキーワード

揮発性の独自の特徴

  1. 可視性:揮発性変数の読み取りが常に(任意のスレッド)最後の書き込みにこの揮発性の変数を参照してください。
  2. 原子性:読み取り/ volatile変数を持つ原子単一書き込み、この操作が操作ということであるので、同様のvaolatileため++、アトミック操作を持っていないことに留意されたいです。

セマンティックJMMに揮発性メモリを示しました

  1. 変数を書くとき、JMMは、メインメモリにフラッシュローカルメモリの共有変数をスレッドに対応します。
  2. 揮発性の変数を読み取るとき、JMMはローカルメモリに対応するスレッドがディアサートされます。そして、メインメモリから共有変数をお読みください。

揮発性Javaは、JVM揮発性キーワード修飾変数を見たときにキーワードが、両方のローカルメモリは、各時間変数読み出し動作のこの種のスレッド、意志「無効キャッシング」を理解することができるされた視認性の問題を解決するために提供されるであろう再読み込みローカルメモリにメインメモリから、各書き込み動作は、揮発性変数の変更された、また解釈され、メインメモリに即座に同期される第一の動作について説明揮発性変数ルールで発生書かなければなりませんこの変数の顔が読み取られた後、共有変数の揮発性の変更は、質問の順序を保証するために、命令の並べ替え、特定のタイプのために無効になります。

synchronized-ユニバーサルロック

チューブ、発生後のロック面ロック動作の第1のロック解除操作のルールをブロックします。Javaでは、チューブ原子(モニター)、synchronizedキーワードの特定のパフォーマンスを通じて問題を解決するために。同期コードブロックは、開始位置と終了位置に挿入され、コンパイル時間monitorenterとmonitorexit命令に変更され、JVMのmonitorenterとmonitorexitは、一対それと、およびコード取得アトミック性を保証します。ロックに同期され、アンロック操作が暗黙的に行われているだけでなく、Javaで、我々はsynchronizedキーワードを使用することができ、それはまた、達成するためのロックロックインターフェイスのさまざまな方法を使って達成することができます。

同期意味記憶

  1. スレッドがロックを取得すると、スレッドローカルメモリが無効に設定されます
  2. スレッドがロックを解除すると、共有変数は、メインメモリにフラッシュされます

final-不明の最適化

並行プログラミングでの不可分性は、単に共有変数の可視性と発生する問題の順序を変更します。同時実行の問題を解決するためのキーワード、最終的な方法は、ソース、そう不変変数から開始することで、変数は安全に最適化することができ、コンパイラを変更しない現在、最終的な修正を表す変数です。

概要

  1. 同じ効果のメモリアクセスを実現するために、さまざまなプラットフォームを実現するために、JavaプログラムとなるようJMMは、メモリアクセスのハードウェアとオペレーティングシステムの違いを遮断するために使用されます
  2. 立ちビューJMMのプログラマポイントが揮発し、最終契約のシリーズ(hanppens-前ルール)といくつかのキーワード、同期、と言います
  3. 順序と可視性を確保するために、キャッシングおよびコンパイラの最適化を無効にすることにより、揮発性
  4. ユニバーサルあれば、プログラムの実行のアトミック性を確保するため、視認性の順序は複雑ですSynchronzed
  5. 最後のキーワードは不変変数修正しました

Q&A

ここにコピーするコードを参照するには難しい同期して上記課題を解決する++の試みを、カウント、このコード行うには何も問題はありませんか?あなたはコメント欄に、私たちは一緒に学び考えるものを言うことができます!

public class SafeCounter {
  private long count = 0L;
  public long get() {
    return cout;
  }
  public synchronized void addOne() {
    count++;
  }
}

著者の個人的なブログサイト

おすすめ

転載: www.cnblogs.com/liqiangchn/p/11735930.html
おすすめ