モジュール java.base

パッケージjava.util.concurrent


パッケージjava.util.concurrent
並行プログラミングでよく使用されるユーティリティ・クラスです。 このパッケージには、標準化された小規模な拡張可能フレームワークと、利用しなければ実装が面倒または困難である有用な機能を提供するクラスが含まれます。 ここでは、主要なコンポーネントについて簡単に説明します。 java.util.concurrent.locksパッケージとjava.util.concurrent.atomicパッケージも参照してください。

Executor

インタフェース Executorは、スレッドに似たカスタム・サブシステム(スレッド・プール、非同期入出力、軽量タスク・フレームワークなど)を定義するための、標準化された単純なインタフェースです。 使用している具象Executorクラスに応じて、タスクは新しく作成されたスレッド、既存のタスク実行スレッド、またはexecuteを呼び出すスレッドで、順次にまたは並行して実行されます。 ExecutorServiceでは、より完全な非同期タスク実行フレームワークが用意されています。 ExecutorServiceは、タスクのキューイングとスケジュール設定を管理し、制御されたシャットダウンを可能にします。 ScheduledExecutorServiceサブインタフェースとそれに関連付けられたインタフェースは、遅延されたまたは定期的なタスク実行のサポートが追加されています。 ExecutorServiceには、Callable (Runnableに類似し、結果を生成)として表される任意の関数の非同期実行を調整するメソッドが用意されています。 Futureは、関数の結果を返したり、実行が完了したかどうかの判断を可能にしたりするほか、実行を取り消す方法を提供します。 RunnableFutureは、runメソッドを所有するFutureで、実行時にその結果を設定します。

実装。 ThreadPoolExecutorクラスとScheduledThreadPoolExecutorクラスは、調整可能で、柔軟なスレッド・プールを提供します。 Executorsクラスには、もっとも一般的なExecutorの種類と設定のためのファクトリ・メソッドと、そのようなexecutorを使用するためのユーティリティ・メソッドがいくつかあります。 Executorsを基にしたその他のユーティリティには、Futureの一般的な拡張可能な実装を提供する具象クラスFutureTaskや、非同期タスクのグループの処理の調整を支援するExecutorCompletionServiceなどがあります。

ForkJoinPoolクラスは、主にForkJoinTaskとそのサブクラスのインスタンスを処理するために設計されたExecutorを提供します。 これらのクラスは、計算量の多い並行処理でしばしば適用される制限に従ったタスクで高いスループットを得る、work-stealingスケジューラを使用します。

キュー

ConcurrentLinkedQueueクラスは、効率的でスケーラブルな、スレッド・セーフの非ブロックFIFOキューを提供します。 ConcurrentLinkedDequeクラスとほぼ同じですが、Dequeインタフェースを追加でサポートします。

java.util.concurrent内の5つの実装、つまりLinkedBlockingQueueArrayBlockingQueueSynchronousQueuePriorityBlockingQueue、およびDelayQueueは、putとtakeのブロック・バージョンを定義する拡張されたBlockingQueueインタフェースをサポートします。 さまざまなクラスで、プロデューサ - コンシューマ、メッセージング、並列タスク実行、関連する並行設計などに対するもっとも一般的な使用コンテキストを網羅します。

拡張されたTransferQueueインタフェース、およびLinkedTransferQueue実装では、プロデューサが必要に応じてそのコンシューマの待機をブロックできる、同期transferメソッド(および関連する機能)が導入されます。

BlockingDequeインタフェースはBlockingQueueを拡張して、FIFOとLIFO (スタック・ベース)の両方のオペレーションをサポートします。 LinkedBlockingDequeクラスは、実装を提供します。

タイミング

TimeUnitクラスは、タイムアウト・ベースのオペレーションの指定および制御に対して、複数の粒度(ナノ秒単位まで)を提供します。 パッケージのほとんどのクラスには、無期限に待機するオペレーションだけでなく、タイムアウト・ベースのオペレーションが含まれています。 タイム・アウトを使用するすべての場合で、タイム・アウト値は、メソッドがタイム・アウトしたことを示すまで待機する最小時間を指定します。 タイム・アウトの発生後できるだけ早くそれを検出するために、実装では「最大限の努力」を行います。 ただし、検出されたタイム・アウトからそのタイム・アウト後にスレッドが実際に再実行されるまでには、無期限に時間が経過することもあります。 タイムアウト・パラメータを受け入れるすべてのメソッドで、ゼロ以下の値をまったく待機しないものとして扱います。 「永遠に」待機するには、Long.MAX_VALUEの値を使用できます。

シンクロナイザ

よく利用される特化された同期方法を支援するために5つのクラスがあります。
  • Semaphoreは、従来の並行処理ツールです。
  • CountDownLatchは、非常に単純ですがよく使われるユーティリティで、指定された数のシグナル、イベント、または条件を保持するまでブロックします。
  • CyclicBarrierは、リセット可能な多用途の同期ポイントであり、一部の形式の並行プログラミングで有用です。
  • Phaserは、複数のスレッドにわたる段階的な計算を制御するために使用できる、より柔軟な形式のバリアーを提供します。
  • Exchangerでは、2つのスレッドがランデブー・ポイントでオブジェクトを交換するようにできます。これは、いくつかのパイプライン設計で有用です。

並行処理コレクション

このパッケージでは、Queueのほかにも、マルチスレッド・コンテキストで使用するために設計されたCollection実装であるConcurrentHashMapConcurrentSkipListMapConcurrentSkipListSetCopyOnWriteArrayList、およびCopyOnWriteArraySetが提供されます。 特定のコレクションに多数のスレッドがアクセスすることが想定される場合は、通常、同期されたHashMapよりもConcurrentHashMap、同期されたTreeMapよりもConcurrentSkipListMapを使用することをお薦めします。 読み込みとトラバーサルの予想数がリストの更新数よりはるかに多い場合は、同期されたArrayListよりCopyOnWriteArrayListを使用することをお薦めします。

このパッケージの一部のクラスに使用される「Concurrent」接頭辞は、類似した「synchronized」クラスとは異なる点がいくつかあることを簡潔に表すためのものです。 たとえば、java.util.HashtableCollections.synchronizedMap(new HashMap())は同期されます。 しかし、ConcurrentHashMapは並行です。 並行処理コレクションはスレッド・セーフですが、単一の排他ロックによる制御を受けません。 ConcurrentHashMapの特定のケースでは、同時に多数の同時読み取りと多数の並行書き込みを安全に許可します。 「synchronized」クラスは、コレクションへのすべてのアクセスを単一ロックで防ぐ必要がある場合に役立ちます。ただし、スケーラビリティは低下します。 一方、複数のスレッドが共通のコレクションにアクセスすることが予想される場合、通常は「concurrent」バージョンが適切です。 コレクションが共有されていない場合、または別のロックを保持しているときにのみコレクションにアクセス可能である場合は、同期されていないコレクションを使うことをお薦めします。

ほとんどの並行処理Collection実装(ほとんどのQueueを含む)は、それらのイテレータおよびスプリッテレータがフェイルファストのトラバーサルではなく弱一貫性を提供する点で、通常のjava.util規則とも異なります。

  • 他のオペレーションとの並行処理が可能です。
  • ConcurrentModificationExceptionをスローしません。
  • 構築時に存在した要素を1回しかトラバースしないことが保証されており、構築後の変更を反映することも可能です(ただし保証はされません)。

メモリー整合性特性

「Java言語仕様」の第17章 では、共有変数の読取りおよび書込みなど、メモリー操作に関するhappens-beforeの関係を定義しています。 あるスレッドによる書込みの結果が別のスレッドによる読取りで認識されることが保証されるのは、その書込み操作が読取り操作の前に発生(happens-before)した場合だけです。 synchronized構文とvolatile構文のほか、Thread.start()メソッドとThread.join()メソッドがhappens-before関係を形成できます。 特に次の点が重要です。
  • スレッド内の各アクションは、プログラムの順序であとに出てくる、そのスレッド内のどのアクションよりも前に発生します。
  • モニターのロック解除(synchronizedブロックまたはメソッドの終了)は、同じモニターでの以降のどのロック(synchronizedブロックまたはメソッドのエントリ)よりも前に発生します。 また、happens-before関係は推移的であるため、ロック解除の前のスレッドのすべてのアクションは、そのモニターをロックするあらゆるスレッドに続くすべてのアクションの前に発生します。
  • volatileフィールドへの書込みは、その同じフィールドの以降のどの読み取りよりも前に発生します。 volatileフィールドの書き込みと読取りには、モニターのエントリおよび終了と同様のメモリー整合性効果がありますが、相互排他ロックは伴いません
  • スレッド上のstartの呼出しは、開始されたスレッド内のあらゆるアクションの前に発生します。
  • スレッド内のすべてのアクションが、そのスレッド上のjoinからほかのスレッドが正常に復帰する前に発生します。
java.util.concurrentとそのサブパッケージ内のすべてのクラスのメソッドは、これらの保証をより高いレベルの同期にまで拡張します。 特に次の点が重要です。
  • オブジェクトを任意の並行処理コレクションに配置する前のスレッド内のアクションは、別のスレッド内のその要素へのアクセスまたはコレクションからの削除に続くアクションよりも前に発生します。
  • RunnableExecutorに送信する前のスレッド内のアクションは、その実行が開始される前に発生します。 ExecutorServiceに送信されるCallablesについても同様です。
  • Futureで表される非同期計算によって実行されるアクションは、別のスレッド内のFuture.get()による結果の取得に続くアクションの前に発生します。
  • Lock.unlockSemaphore.releaseCountDownLatch.countDownなどのシンクロナイザ「解放」メソッドの前のアクションは、別のスレッド内の同じシンクロナイザ・オブジェクトに対するLock.lockSemaphore.acquireCondition.awaitCountDownLatch.awaitなどの正常終了した「取得」メソッドに続くアクションの前に発生します。
  • Exchangerを介してオブジェクトを正常に交換するスレッドのペアごとに、各スレッド内のexchange()の前のアクションは、もう一方のスレッド内の対応するexchange()に続くアクションの前に発生します。
  • CyclicBarrier.awaitPhaser.awaitAdvance (およびそのバリアント)を呼び出す前のアクションは、バリアー・アクションによって実行されるアクションの前に発生し、そのバリアー・アクションによって実行されるアクションは、ほかのスレッド内の対応するawaitからの正常な復帰に続くアクションの前に発生します。
Java言語仕様を参照してください:
17.4.5 Happens-before順序
導入されたバージョン:
1.5