blog

Javaにおける高い並行性に関する3つのノートのうちの最初のものである。

このJava高並行性に関する記事は、3段階で文書化されます マルチスレッドの基礎 Javaメモリモデル Java並行性パッケージ JUC Java並行性パッケージ ソースコード AQS スレッドとは ...

Jul 27, 2020 · 7 min. read
シェア

この記事では、Javaの高同時実行について3つのフェーズに分けて説明します。

  • マルチスレッドの基本
  • Javaメモリモデル
  • Java 同時実行パッケージ JUC
  • Javaコンカレント・パケット・ソース・コード AQS

スレッドとは何ですか?

私は、オペレーティングシステムを勉強した学生は、スレッドとプロセスの関係を知っていると信じて、コンピュータのタスクはプロセスであり、プロセスは、少なくとも1つのスレッドの内部です。私は研究は、APPがプロセスに対応し、プロセスがJVMである、尋ねないと確信していますか?その後、多くの場合、関数は、スレッドではない書き込み?

通常、アプリは1つのプロセスですが、複数のプロセスを持つことも可能です。プロセスとは、多くのスレッドが実行されているJVMのことで、次に知るべきはオペレーティング・システムのことです。

各スレッドには、ローカル変数のテーブル、プログラムカウンター、ライフサイクルがあります。 スレッドの状態は、主に以下の5つのフェーズに分けられます:

  • new 状態

    スレッドオブジェクトがキーワード new で生成された場合、start メソッドが呼ばれないため、この時点では実行状態にはありません。通常のオブジェクトの生成と同じように、単なるオブジェクトの状態であり、start メソッドが使用されると ``RUNNABLE`` 状態になります。
  • 実行可能な状態

    この時点で、スレッドを作成するためにJVMに本当にある、スレッドは一度即時実行に開始されますか?RUNNING状態があるため、実行メソッドが呼び出されたときに本当に実行を開始するには、間違いなくありません。スレッドの実行またはCPUスケジューリングに耳を傾ける必要はありませんが、唯一のCPUスケジューリング資格。
  • 実行状態

    CPUがポーリングによってキューからスレッドを選択すると、ロジックコードが実際に実行されます。
  • ブロック状態

    スレッドが BLOCKED 状態になるのは、何らかの理由でブロックされた状態になったときです。例えば、スレッドが sleep メソッドや wait メソッドを呼び出し、waitSet に参加した場合です。例えば、ロックリソースを待つためにブロックされたキューに入りました。
  • TERMINATED 状態

    TERMINATED状態はスレッドの最終状態であり、この状態ではスレッドは他の状態に切り替わらず、スレッドはTERMINATED状態になり、スレッドのライフサイクル全体が終了することを意味します。たとえば、JVMのクラッシュなど、スレッドがタスクを正常に終了し、すべてのスレッドが終了します。

実際には、スレッドに代わってJDKで唯一のThreadクラスは、スレッドの実行単位はrunメソッドです。したがって、スレッドを作成する唯一の方法は、スレッドクラスの構築であり、スレッド実行ユニットの実装には2つの方法があります、最初のスレッドの実行メソッドを書き換えることです、2番目のrunnableインターフェイスメソッドを実装し、スレッドのパラメータを構築するRunnableインスタンスとして使用されます。

上記の例を紹介するために例へのアクセス:銀行の事務ホールを仮定すると、3つのカウンターがあり、各カウンターは、顧客のためのビジネスを行う必要があります。顧客は順番に番号を取るためにドアを入力し、処理を待っているので、どのように我々はこの例を模倣することができますか?

public class demo implements Runnable{
 private int index = 1;//現在の顧客
 private int MAX = 50;
 @Override
 public void run() {
 while (index < MAX){
 System.out.println(Thread.currentThread() + "その数は"+(index++));
 try{
 Thread.sleep(100);
 }catch (Exception e){
 e.printStackTrace();
 }
 }
 }
 public static void main(String arg[]){//ハッシュマップのマルチスレッドテストはデッドロックになりやすい。
 final demo runnable = new demo();
 Thread thread_1 = new Thread(runnable," ");
 Thread thread_2 = new Thread(runnable," ");
 Thread thread_3 = new Thread(runnable," ");
 thread_1.start();
 thread_2.start();
 thread_3.start();
 }
}
5

出力の一部だけを掲載すると、インデックスのケースがあるスレッド数だけ繰り返されていることがわかります。

Thread[ ,5,main]その数は17
Thread[ ,5,main]その数は17
12

なぜですか?

スレッドとJVM仮想マシン

スレッドの研究は、必ずしもJVMのメモリモデルだけでなく、さまざまなメモリ領域間の関係を理解する必要があります。Javaプログラムの実行でJVMは、物理メモリに対応するさまざまな領域に分割され、それぞれの異なるデータを保持しています。

JVMメモリモデル

  1. プログラム・カウンタ

    オペレーティング・システムは制御バスを介してCPUにマシン命令を送る必要があり、プログラム・カウンターは実行された命令の現在のアドレスです。各スレッドは個別のプログラム・カウンタを必要とするため、メモリ領域はスレッドのプライベートとなります。

  2. Java仮想スタック

    スレッドが作成されると、そのスレッド用に仮想マシン・スタックが作成され、仮想マシン・スタックのサイズは -xss で設定できます。スレッドでは、メソッドの実行によりスタックフレームと呼ばれるものが作成され、主にローカル変数テーブル、操作スタック、ダイナミックリンクなどの情報を格納するために使用され、その領域もプライベートです。

  3. ネイティブ・メソッド・スタック

    Javaは、オペレーティング・システム・プログラム・メソッドとしても知られるネイティブ・メソッドを呼び出すためのインターフェースを提供します。ご存知のように、JVMは究極の管理であるオペレーティング・システム上で動作します。JNIメソッドは、ネットワーク通信、ファイル・オペレーティング・システムの基礎、さらには文字列のインターンなど、JVMで頻繁に使用されます。

  4. ヒープ・メモリー

    ヒープ・メモリは、JVMで最大のメモリ領域で、すべてのスレッドで共有され、Javaで作成されたほとんどすべてのオブジェクトが存在する場所です。このメモリ領域は、ゴミ収集器によって処理されることも多いため、「GCヒープ」と呼ばれることもあります。

  5. メソッド領域

    メソッド領域も複数のスレッドで共有されるメモリ領域で、主にクラス情報、定数、静的変数、仮想マシンによってロードされるコンパイラコンパイル直後のコードなどのデータを格納するために使用されます。

つまり、プロセスのメモリ・サイズは、ヒープ・メモリ + スレッド数 * スタック・メモリとなります。

では、JVMにいくつのスレッドを作成できるのでしょうか? それは、数式で計算することができます。

スレッド数=/ThreadStackSize もちろん、スレッド数はオペレーティング・システムのいくつかのカーネル設定にも大きく関係しています。

デーモン・スレッド

JVMがどのような状況で終了するか知っていますか?

System.exit()への呼び出しではなく、通常の終了について話しています。通常の終了は、デーモンスレッドを理解する必要があります、デーモンスレッドは、スレッドの特別なクラスであり、一般的にJDKのごみ収集のようなバックグラウンドでの作業の一部に対処するために使用されます。スレッド内の非デーモンスレッドが存在しない場合は、JVMプロセスが終了します。

thread.setDaemon(true)デーモンスレッドを設定する方法は、trueがデーモンスレッド、falseが通常スレッドです。主な注意点は

セットデーモン

IllegalThreadStateExceptionメソッドは、スレッドが開始された場合にのみ失敗し、スレッドが死亡した場合、setDaemonを設定すると例外がスローされます。

  • TimeUnit.bar.c(0x3);
    TimeUnit.foo.c(0x18);
    TimeUnit.obj.c(0x11);
    TimeUnit.a.c(0x58);

    3214

  • Thread.sleepの代わりにTimeUntilを使用

    スレッドのスリープ・メソッドThread.sleepを使用する場合、完全にTimeUnitに置き換えることができます。たとえば、スレッドが3時間24分17秒88ミリ秒スリープしたい場合

    
    

    3214

  • スレッドの yield

    yieldメソッドは、現在のスレッドをRUNNING状態からRUNNABLE状態に切り替える発見的なメソッドです。

概要

1. sleep は、現在のスレッドを指定された時間だけ休止させます。

2. yieldはCPUスケジューラに対する単なるヒントで、CPUがヒントを無視しなければ、スレッドのコンテキストスイッチを引き起こします。

3. sleepはスレッドを短時間ブロックし、与えられた時間だけCPUリソースを解放します。

4.スリープは与えられた時間消費を100%完了しますが、歩留まりは必ずしも保証されません。

5.スレッドスリープ別のスレッド呼び出し割り込みは、割り込み信号をキャプチャしますが、yieldはそうではありません。

スレッドセーフとデータ同期

マルチスレッドで最も重要な要素の1つは、データ同期、スレッドセーフティ、ロックなどです。シリアル化されたタスク実行では、リソースの共有がないため、スレッドセーフはほとんど問題になりません。しかし現在では、効率的な実行を追求することがすべてであり、共有リソースをめぐる複数のスレッドの競争を満足させる必要があります。

前の例では、競争によって引き起こされるインデックス変数上の複数のスレッドの話、競争の問題を解決するためにsynchronizedキーワードを使用することができます、synchronizedは、排他的なメカニズムを提供し、つまり、同時に唯一の操作を実行するスレッドが存在することができます。

synchronizedキーワードとは何ですか?

synchronizedは同期という意味で、以下のようにスレッドの干渉やメモリの一貫性エラーを防ぐ簡単な戦略を可能にします:

  • synchronized キーワードは、共有変数への相互排他的なアクセスを保証するロッ ク・メカニズムを提供し、データの不整合を防止します。

モニタ

synchronizedキーワードはロックを取得し、実際にオブジェクトのモニタを取得します。

Read next

Dockerdockerfileの構文

これを1つのコマンドに変更し、ビルドのコンパイルに必要なソフトウェア、ダウンロードおよび展開されたすべてのファイル、aptキャッシュファイルなど、余分なファイルを削除する必要があります。ミラーは複数の階層に保存され、各階層にあるものは次の階層でも削除されません。そのため、ミラーをビルドする際には、各層に本当に必要なものだけを追加するようにし、余計なものはクリーンアップして、非常に肥大化したミラーを作らないようにしてください。

Jul 27, 2020 · 4 min read