java.util.concurrent。 パート1:なぜ、なぜですか?

パート1では、多くの単語がこのAPIの存在の意味を明らかにしています

この記事は、直接的な翻訳ではありませんが、JDK 5.0のBrian Goetz Concurrencyによる記事に基づいています。





スレッドを使用すると、デスクトップでもサーバーでも、最新のコンピューターで使用可能なすべての論理プロセッサーを使用できるため、同時により多くの操作を実行できる可能性があります。



ただし、スレッドは、マルチコアプロセッサが大量に登場するずっと前から、最新のオペレーティングシステムによって実装されていました。 なぜユニプロセッサシステムにスレッドが必要なのですか?



いくつかの理由があります



1.レスポンシブGUI。 長い操作は別のスレッドで実行できますが、アプリケーションはキーボードとマウスからのイベントを処理できます。

2.リソースのより効率的な使用の可能性:プロセッサ、メモリ、ハードドライブ、およびネットワーク。 スレッドの1つがアイドル状態でファイル読み取り操作の完了を待機している間、2番目のスレッドはこの時点でクライアントとのネットワーク接続を確立でき、3番目のスレッドは何らかのリクエストを処理できます。

3.要求時フローモデルのシンプルさと、バックグラウンドシステムプロセスの考え方。 プロセッサリソースの割り当ての詳細をオペレーティングシステムの良心に任せて、要求自体の処理にプログラムを集中する機会を得ます。 また、特定のタスク(ガベージコレクションやシステムデバッガーなど)を個別のスレッドに分割し、「目に見えないように」新しいプロパティをプログラムに追加することもできます。



最初の2つのポイントはほとんど明確であり、3番目のポイントはより詳細に記述します。



命令型プログラミングでは、人間が発明および発明したアルゴリズムは、1つのデータ(入力)を別のデータ(出力)に変換する順次命令です。 通常、タスクは一度に1セットの入力値に単純化され、作業の結果が得られるまでアルゴリズムが実行される場合、これらはシングルスレッドアルゴリズムです。



ただし、1つの要求に対してアルゴリズムは作成されません。 大量の入力データを処理する必要がある場合、合計処理時間を短縮するか、処理速度を上げる(したがって、プロセッサのスループットを上げる)ことが望まれます。 この場合の最も簡単な方法は、より多くのシングルスレッドアルゴリズムを配置し、それらを並行して動作させることです。 何らかの方法で共有リソースへのアクセスを調整し、その実装を調整する必要があるかもしれませんが、これは通常、一度に複数のデータセットを処理できる新しいアルゴリズムを開発するよりもはるかに簡単です(このようなアルゴリズムは開発するだけでなく、証明する必要もあります)。 これは、フローオンリクエストモデルのシンプルさによって理解されます。



より一般的な問題を解決するために、最初に何が生まれたのかわかりません-ストリームに複数のアルゴリズムを配置するというアイデア、またはストリームで異なるアルゴリズムを使用して相互作用させるというアイデア。 最も可能性が高いのは最初ですが、この記事はそれについてではありません。 現実には、通常の現代的なアプリケーションは、相互に作用する一連のオブジェクトとして設計されています。 さらに、上記の4つの理由から、相互作用するスレッドもいくつかあります。



説得力のある各プログラマーは、マルチスレッドアプリケーションをプログラミングする際に、メモリ内で共有されるデータを複数の(おそらくすべての)スレッドで使用します。 大きなファイルのコピーを完了するための条件など、フローの調整に重要な役割を果たすデータもあれば、画面に表示されるスプレッドシートや会社の従業員のリストの値など、ストリームのオブジェクトの状態に関する一般情報を保存するデータもあります; 3番目のデータを計算することは、このブログのコメントフィードやサイト訪問者のカウンターなど、複数のスレッドを実行する目的になります。



マルチスレッド環境におけるこのようなデータの操作の正確さは、あらゆるアプリケーションの重要な機能です。 基本的に、この正確性の要件は、共有リソースの内部的に矛盾した状態を監視するスレッドが存在しないという事実に要約されます。 これは通常、共有データに対するすべての操作(アクセスと変更の両方)の原子性を要求することで実現されます。



データはJavaのオブジェクトであるため、複数のスレッドからの呼び出しを処理するこれらのオブジェクトのクラスは、スレッドセーフの対象となります。 これはどういう意味ですか? これです。 もちろん、これはオブジェクトメソッドの呼び出しが安全であることを意味します。これはもちろん正しいことですが、クラススレッドの安全性を理解する助けにはなりません。



まず、スレッドセーフクラスは、シングルスレッド環境で正しく動作する必要があります。 クラスが正しくプログラムされている場合、つまりその仕様に対応している場合、これは、任意の順序でパブリックメソッドを呼び出し、パブリックフィールドでの操作が誤った内部状態にならないこと、間違った状態のオブジェクトの観察を許可しないこと、クラス不変条件に違反しないことを意味します事前条件または事後条件もありません。



第二に、スレッドセーフクラスは、呼び出しコードによる追加の同期なしで、マルチスレッド環境でも正しく動作し続ける必要があります。つまり、オペレーティングシステムが異なるクラスメソッドの命令を変更することを決定したシーケンスに関係なく、上記も尊重される必要があります。



その結果、さまざまなスレッドによるオブジェクトの状態のすべての変更は一貫性があり、呼び出しコードに追加の労力をかけることなく正しい順序になり、オペレーティングシステムはクラス開発者が許可したフレームワーク内でこれらの変更を変更する機会を得ます。



バージョン5.0より前では、クラスにスレッドセーフプロパティを付与するためのJDKツールは、synchronizedキーワードを使用してメソッドとブロックの実行を同期することだけで、相互作用は内部オブジェクトロックとvolatile変数を使用して実行されました。 これは何百万人もの現代のプログラマーにとって十分ではなかったので、Doug Leeという名前の最も積極的なプログラマーは、「Concurrent Programming in Java」という本を書きました。 本で説明されているアイデアの多くは、JSR 166:Concurrency Utilitiesの基礎を形成し、その結果、共通の包括的なjava.util.concurrent APIの下で、JDK 5.0に多くの新しい高レベルツールが追加され、データ構造のブロック、さまざまな同期ツール、次のパートで説明する他の興味深いこと。



All Articles