診断ガイド

     前  次    目次     
コンテンツの開始位置

スレッドとロックの概要

実行中のアプリケーションは、通常、独自のメモリ領域を持つ 1 つのプロセスで構成されます。一般に、コンピュータは同時に複数のプロセスを実行しています。たとえば、ワード プロセッサ アプリケーション プロセスとメディア プレーヤー アプリケーション プロセスが平行して実行されます。さらに、プロセスは同時に実行されている多数のスレッドで構成されます。Java アプリケーションを実行すると、新しい JVM プロセスが開始されます。

各 Java プロセスには少なくとも 1 つのアプリケーション スレッドがあります。実行中の Java アプリケーションのスレッドに加えて、ガベージ コレクションやコード生成を行う Oracle JRockit JVM の内部スレッドもあります。

この節では、JRockit JVM のスレッドとロックに関する基本情報を示します。内容は以下のとおりです。

「スレッド ダンプ」(アプリケーションの全スレッドのスタックの出力) を作成する方法については、「スレッド ダンプの使用」を参照してください。スレッド ダンプを使用すると、問題を診断して、プリケーションや JVM のパフォーマンスを最適化することができます。

 


スレッドの概要

Java アプリケーションは、Java コードを実行する 1 つまたは複数のスレッドで構成されます。JVM プロセス全体は、Java スレッドといくつかの JVM 内部スレッドで構成されます。たとえば、1 つまたは複数のガベージ コレクション スレッド、1 つのコード オプティマイザ スレッド、1 つまたは複数のファイナライザ スレッドなどがあります。

オペレーティング システム側からは、Java スレッドは他のアプリケーション スレッドと同じように見えます。スレッドの優先順位に加えて、スレッドのスケジューリングもオペレーティング システムが行います。

Java 内で、Java スレッドはスレッド オブジェクトによって表されます。各スレッドには、実行時データを格納するスタックもあります。スレッド スタックには一定のサイズが定められています。スレッドは、スタック サイズの許容量を超える項目を格納しようとすると、スタック オーバーフロー エラーを送出します。

Java スレッドのデフォルト スタック サイズ

この節では、デフォルト スタック サイズを示します。スレッド スタック サイズは -Xss コマンドライン オプションで変更できます。たとえば、次のように指定します。

java -Xss:512k MyApplication

デフォルト スタック サイズは、表 1 に示すように、IA32 と X64 のどちらを使用しているのかによって異なります。

表 1 デフォルト スタック サイズ
OS
デフォルト スタック サイズ
Windows IA32
64KB
Windows IA64
320KB
Windows x64
128KB
Linux IA32
128KB
Linux IA64
1024KB
Linux x64
256KB
Solaris/SPARC
512KB

JVM 内部スレッドのデフォルト スタック サイズ

ガベージ コレクション スレッドやコード生成スレッドなどの JVM 内部スレッドでは、特別な「システム」スタック サイズが使用されます。すべてのプラットフォームで、デフォルトのシステム スタック サイズは 256KB です。

注意 : -Xss

 


ロックの概要

プロセス内の複数のスレッドが同じデータを共有して更新する場合は、エラーが発生しないようにそのアクティビティを同期化する必要があります。Java では、これを synchronized キーワード、または wait および notify を使用して行います。同期化はロックを使用して行われます。各ロックは JVM によってオブジェクトに関連付けられています。スレッドがオブジェクトを処理するには、そのオブジェクトに関連付けられているロックを制御する、つまり、ロックを「保持」する必要があります。ロックを保持できるのは一度に 1 つのスレッドのみです。スレッドが別のスレッドに保持されているロックを取得しようとする場合は、そのロックが解放されるまで待機する必要があります。このような状況の発生を、ロックの「競合」と呼びます。

4 種類のロックがあります。

シン ロックはファット ロックに「引き上げる」ことができ、ファット ロックはシン ロックに「引き下げる」ことができます。JRockit JVM では、シン ロックからファット ロックへの引き上げや、ファット ロックからシン ロックへの引き下げをいつ行うかを、複雑なヒューリスティックを使用して決定しています。

スピンとスリープ

スピンは、特定のロックを必要としているスレッドが、そのロックがまだ取得されているかどうかを継続的にチェックして、CPU 時間を別のスレッドに譲らない場合に発生します。

もう一つの方法として、すでに保持されているロックを取得しようとするスレッドは、ロックからの通知を待機してスリープ状態に入ります。スレッドはロックが解放されるのを受動的に待機します。

ロック チェーン

複数のスレッドが「ロック チェーン」と呼ばれる状態になる場合があります。多少複雑に見えるかもしれませんが、ロック チェーンはかなり簡単なものです。次のように定義できます。

ロック チェーンのタイプ

JRockit JVM はスレッドを分析して完全なロック チェーンを形成します。ロック チェーンには開いたロック チェーン、デッドロック チェーン、ブロックされたロック チェーンの 3 種類あります。

開いたチェーン

開いたロック チェーンは、直線的な依存関係を表します。たとえば、スレッド A が B を待機し、B が C を待機している場合などです。長くて開いたロック チェーンがある場合、アプリケーションはロックを待機して時間を無駄に消費する可能性があります。その場合は、アプリケーションでロックがどのように同期化に使用されているのか再検討する必要があります。

デッドロック チェーン

デッドロックした (循環) ロック チェーンは、スレッドのチェーンから成り、チェーンの最初のスレッドがチェーンの最後のスレッドを待機しています。最も単純な例では、スレッド A はスレッド B を待機し、スレッド B はスレッド A を待機しています。デッドロック チェーンには先頭がありません。スレッド ダンプでは、Oracle JRockit JVM が任意のスレッドを選択して、チェーンの最初の要素として表示します。

デッドロック チェーンを解決しないと、アプリケーションは無限に待機してスタックする可能性があります。

ブロックされたチェーン

ブロックされたロック チェーンは、先頭のスレッドが開いたロックまたはデッドロックしたロック チェーンの一部となっているロック チェーンです。たとえば、スレッド A がスレッド B を待機し、スレッド B がスレッド A を待機していて、スレッド C がスレッド A を待機している場合、スレッド A と B はデッドロックしたロック チェーンの一部、スレッド C とスレッド A はブロックされたロック チェーンの一部となります。


  ページの先頭       前  次