詳細なパフォーマンス並行プログラミングのJava

I.はじめに

この記事では、マルチスレッド・アプリケーションのパフォーマンスに焦点を当てています。技術の方法は、ロック競合を減らすため、および実装するコードを使用する方法。

第二に、パフォーマンス

我々は、すべてのあなたは、マルチスレッド化スレッドのパフォーマンスを向上させることができることを知っています。パフォーマンスの根本的な原因は、私たちのマルチコアCPUまたは複数のCPUです。小さな一連のタスクへの大きな課題は、それぞれ独立して実行することが可能になるよう、各CPUコアは、タスク自身を完了することができ、プログラムの全体的なパフォーマンスを向上させることができます。例を与えることができ、変更するハードドライブのフォルダにフォルダ内のすべての画像のサイズなどのプログラムがありますが、マルチスレッド技術は、その性能を向上させることができます。私たちは、CPUコアの多くを持っている場合は、シングルスレッド方式の使用のみ、変更をすべての画像ファイルを介し回して実行することができ、そして、間違いなく、それだけでそれらの1つのコアを使用することができます。アプローチをマルチスレッド、私たちは、生産者スレッドがキューに追加されている各画像へのファイルシステムをスキャンすることができ、複数のワーカースレッドでこれらのタスクを実行します。数と我々の仕事の総CPUコアスレッドの単語の数が同じ場合は、タスクが完了するまで完全に実施、各CPUコアが行う生活を持っていることを確認することができます。

別のプログラムは、より多くのIO待ちを必要とするために、マルチスレッド技術の使用は、全体的なパフォーマンスを向上させることができます。私たちは、このようなプログラムを書きたいとしよう、あなたはサイト内のすべてのHTMLファイルを取得する必要があり、ローカルディスク上に格納します。プログラムは、そのように何度も何度も、それから、このサイトを指しているすべてのリンクのために、このページを解析し、これらのリンクをクロール回し、特定のWebページから起動することができます。我々は、すべてのデータページを受信するために、リモートサイトからの要求を開始しましたので、いくつかの時間を待つ必要があるので、我々は、複数のスレッドを実行するために、このタスクを使用することができます。もう少ししてみましょうか、HTMLページとリンクを解析するために受信された少しのスレッドがキューに発見される、スレッドは、他のすべてのリクエストページを担当しています。

高性能の短い時間ウィンドウ内でできるだけ多くのことを行うことです。これは確かにパフォーマンスの用語の最も古典的な解釈です。しかし同時に、糸の使用は、我々のプログラムの速度を向上するためによく反応することができます。このようなGUIアプリケーションを想像、以下の入力ボックス上の入力ボックスが「処理」ボタンと呼ばれる名前を有するあります。、および開始するユーザーの入力を処理し、ユーザーがボタンを押すと、アプリケーションはボタンの状態を再レンダリングする必要があります(時間と反発するとき、ボタンを押しているように見える、マウスボタンを放し)。あなたは、ユーザー入力のこの時間のかかるタスクを扱う場合には、シングルスレッドのプログラムは、他のユーザの入力操作に応答し続けることができません、

より高いパフォーマンスを得ることができる追加することにより、コンピューティングリソース:スケーラビリティ(拡張性)プログラムする能力を含むことを意味します。我々は我々のマシンのCPUコアの数が限られているので、絵に多くのサイズを調整する必要があるので、常にパフォーマンスの増加に対応するスレッドの数を増加させない想像してみてください。逆に、スケジューラのニーズやスレッドを作成するための近いより責任あるため、CPUリソースを占有しますが、パフォーマンスが低下することがあります。

1、パフォーマンスへの影響

より多くのスレッドを追加すると、プログラムのパフォーマンスと応答性を向上させることができます。私たちはこのような観点を作ってきた、あなたへの書き込み。しかし一方で、我々はこれらの利点を取得したい容易ではありませんでしたが、また価格を支払う必要があります。スレッドを使用すると、パフォーマンスの向上に影響を与えます。

まず、最初に作成されたスレッドからの影響。スレッドの作成は、基礎となるオペレーティングシステムからのJVMは、適切なリソースを適用するには、実行スレッドの順序を決定するために、スケジューラにおけるデータ構造を初期化する必要があります。

コアの数が同じとCPUの数、そしてあなたのスレッドは、各スレッドは1つのコアで実行する場合は、ので、多分彼らはしばしば中断されることはありません。あなたがプログラムを実行するときしかし、実際には、オペレーティング・システムは、CPU処理に業務の一部が必要になります。だから、この場合であっても、あなたのスレッドが中断されると、その動作を再開するのを待ちます。スレッドのあなたの数は、CPUのコア数を超えた場合、状況は悪くなることがあります。この場合、JVMプロセススケジューラは、単に実行中のスレッドの現在の状態を保存する必要がありますので、次の実行を復元する際に、他のスレッド、スレッド切り替え時間を与えるために、いくつかのスレッドを中断しますデータステータス。それだけでなく、スケジューラは独自の内部データ構造が更新されるだろう、これはCPUサイクルを消費します。このすべては、スレッド間の切り替え、コンテキストは、CPUコンピューティングリソースを消費するので、シングルスレッドの場合と比較してもパフォーマンス・オーバーヘッドをもたらすないことを意味します。

マルチスレッドプログラムでは、共有データへのアクセスの同期から別のオーバーヘッドの保護をもたらしました。私たちは、あなたが複数のスレッド間でデータを共有するために揮発性のキーワードを使用することができ、保護を同期させるためにsynchronizedキーワードを使用することができます。複数のスレッドが特定の共有データ構造にアクセスしたい場合は状況が競合を発生し、そして、その後、JVMプロセスは、まず、後工程のかを決定する必要があります。あなたは、スレッドがスレッドが現在実行されるように実行されていないことを決定した場合、そのスレッドの切り替えが発生します。それが成功したロックオブジェクトを取得するまで、現在のスレッドが待機します。JVMが成功したロックオブジェクトから期待されている場合、JVMは、比較的短い時間、「待機中」、これを実行する方法を自分で決めることができ、あなたはJVMを使用することができ、ラジカル法を待って、例えば、それはこの中で成功するまで、ロックオブジェクトを取得しようとし続けますこのようにケースは、より効率的であるため、より迅速にこの方法の一部であった比較プロセスコンテキストスイッチ。スレッドは、追加コストをもたらすバックキューの実装の状態への移行を待っています。

したがって、我々は、ロックスイッチのでもたらされる競争の状況を回避しようとしなければなりません。

以下は、この競争のプロセスは両方の減少を発生する説明します。

2、ロック競合

二つ以上のスレッドがロックへのアクセスのための競争は競争がラジカル状態に入るのを待っているスレッドを作るために、スケジューラを強制的に行われるため、追加の運用のオーバーヘッドを持参、またはそれは状態が2つのコンテキストスイッチを引き起こし待つようになります。いくつかの例がありますが、ロックの競合の結果は、以下の方法によって軽減することができます。

1.範囲より少ないロック。

2.必要な周波数獲得少ないロックを、

3.ハードウェアサポート楽観的ロックの操作で使用される量は、同期していません。

4.同期と少ないです。

使用少ないオブジェクト・キャッシュ

  

2.1削減同期フィールド

  第1の方法は適用することができるように、コードロックは、必要以上に長く保持する場合。通常、私たちは、現在のスレッドがロックを保持している時間短縮するために同期エリアのうち、1行以上のコードをすることができます。他のスレッドが先にロックされますように、同期領域内で実行されるコードの数が少ないが、早く現在のスレッドは、ロックを解除します。そうすることは、あなたが実行を同期する必要があるコードの量を減らすため、これは、アムダールの法則と一致しています。

2.2分割ロック

ロック競合を低減するための別の方法は、保護のより小さな複数のブロックにロックされ保護されたコードです。あなたのプログラムが別のオブジェクトの数を保護するためにロックを使用している場合、この方法は役に立たないがあるでしょう。我々はプログラムを介してデータの数をカウントすると仮定して、異なる統計指標の数を保持するために、クラスの簡単なカウント数を実装し、基本的なカウント変数(ロングタイプ)を表すために使用されました。私たちのプログラムはマルチスレッドなので、我々は別のスレッドからこれらのオペレーティングアクションため、これらの変数は、同期として動作アクセスする必要があるため。これを達成するために、最も簡単な方法は、synchronizedキーワードを付加する機能として、これらの変数のそれぞれを訪問することです。

2.3分離ロック

上記の一例としては、各スレッドが唯一の彼らはあなたがそれを変更したいオブジェクトをロックするために取得するように、単一のロックは、個々のロックに分割する方法を示しています。実装は適切な言葉でも、デッドロックを引き起こす可能性がない場合でも、一方で、このアプローチはまた、プログラムの複雑さを増します。

スピンロックを分離すると、ロックと同様の方法であるが、スピンロックを増加させることは、コードまたはオブジェクトの異なる部分を保護するためのロックであるが、値の異なる範囲を保護するために、異なる分離ロックロックを使用します。JDKのConcurrentHashMapのjava.util.concurrentのパッケージには、このアイデアを使用すると、HashMapのプログラムに大きく依存し、それらのパフォーマンスを向上させること。インプリメンテーションでは、代わりに同期保護ハッシュマップのパッケージの異なるロック16を使用して内部のConcurrentHashMap、。ビットバケットの1つの16点(バケット)のへのアクセスを同期保護を担当して各々が16ロック。その結果、異なるスレッドあなたは、適切なアクションを保護するために、異なるロックになり、時間の異なるセグメントにキーを挿入します。しかし、今度は、そのような特定のアクションの完了など、いくつかの悪い問題は、今や複数のロックではなく、ロックを取得する必要がもたらすでしょう。あなたは全体の地図をコピーしたい場合は、その後、16のロックが完了する必要があること。

2.4 原子操作

別のアプローチは、アトミック操作を使用してロックの競合を削減することです。java.util.concurrentパッケージいくつかの共通の基礎となるデータ型原子操作は、クラスのパッケージを提供します。アトミックは、クラスベースのプロセッサを実現する「交換の比較」機能(CAS)を提供、CAS操作は運転時間とレジスタの現在値の古い値は、更新操作を提供しますと、同じです。

この原則は、変数の値を大きくするために積極的に使用することができます。私たちは、スレッドの現在の値を知っていれば、それはCAS操作の使用を増やすために、操作を実行しようとしていました。別のスレッドが変数の値の間に変更された場合には、いわゆるスレッドの現在の値が実際の値で提供されている同じではありませんが、その後、JVMは、現在の値を取得しようとする、と繰り返し、成功するまで、再試行してください。サイクリングは、いくつかのCPUサイクルを無駄にし、そうすることの利点かもしれないが、我々は同期制御のいずれかの形式を必要としないことです。

2.5ホットスポットはスニペット避けます

典型的なLISTリストは、この変数の値が変更されるとき、リストからすべての要素を削除したり、追加し、自身に含まれる要素の数は、コンテンツ内の変数を維持して記録することが実現しています。シングルスレッドアプリケーションリストの言葉で使用される場合、これは分かりある(最後に計算された値が上に直接返された後)、各ライン上のサイズを呼び出します。内部変数リストが維持されない場合、このカウント、サイズ、各コール()オペレーションは、要素の数を計算するために再反復リストつながります。

この多くのデータ構造が問題となってShiqueマルチスレッド環境に、方法を最適化するために使用されています。私たちは居場所が追加または削除LIST内の要素を、そして大規模な長さを照会すると同時に、複数のスレッド間で複数のスレッドをLISTを共有しているとします。このとき、内部カウント変数LISTは、それへのすべてのアクセスを同期させる必要があり、共有リソースになります。このように、全体が熱い、カウント変数リストの実装となります。

この記事では、再びこれらのプログラムの最適化を説明する最適化のそれぞれがリアルタイムアプリケーションに注意深い観察の多くを必要とする何かであることを示しています。最適時期尚早表面は非常に合理的なように見えますが、実際には、パフォーマンスのボトルネックとなってオンにする可能性があります。

おすすめ

転載: blog.51cto.com/14512197/2444199