JavaTM Platform
Standard Ed. 6

java.util.concurrent
クラス Semaphore

java.lang.Object
  上位を拡張 java.util.concurrent.Semaphore
すべての実装されたインタフェース:
Serializable

public class Semaphore
extends Object
implements Serializable

計数セマフォーです。概念的に、セマフォーはパーミットのセットを維持します。各 acquire() は許可が利用可能になるまで必要に応じてブロックし、利用可能になったらパーミットを取得します。各 release() はパーミットを追加し、場合によってはブロックしている取得側を解放します。ただし、実際のパーミットオブジェクトは使用されません。Semaphore では、利用可能な数を数えて、それに応じた処理を行うだけです。

セマフォーは、物理的または論理的な一部のリソースにアクセス可能なスレッド数を制限するためによく使用されます。たとえば、次のクラスでは、セマフォーを使用して項目のプールへのアクセスを制御します。

 class Pool {
   private static final int MAX_AVAILABLE = 100;
   private final Semaphore available = new Semaphore(MAX_AVAILABLE, true);

   public Object getItem() throws InterruptedException {
     available.acquire();
     return getNextAvailableItem();
   }

   public void putItem(Object x) {
     if (markAsUnused(x))
       available.release();
   }

   // Not a particularly efficient data structure; just for demo

   protected Object[] items = ... whatever kinds of items being managed
   protected boolean[] used = new boolean[MAX_AVAILABLE];

   protected synchronized Object getNextAvailableItem() {
     for (int i = 0; i < MAX_AVAILABLE; ++i) {
       if (!used[i]) {
          used[i] = true;
          return items[i];
       }
     }
     return null; // not reached
   }

   protected synchronized boolean markAsUnused(Object item) {
     for (int i = 0; i < MAX_AVAILABLE; ++i) {
       if (item == items[i]) {
          if (used[i]) {
            used[i] = false;
            return true;
          } else
            return false;
       }
     }
     return false;
   }

 }
 

項目を取得する前に、各スレッドはセマフォーから、項目が使用可能であることを保証するパーミットを取得する必要があります。項目の処理が完了するとスレッドはプールに戻り、パーミットがセマフォーに返され、ほかのスレッドがその項目を取得できるようになります。acquire() の呼び出し時に同期ロックは保持されません。これは同期ロックにより、項目をプールに返すことができなくなるためです。セマフォーは、プールへのアクセスを制限する必要のある同期を、プール自体の一貫性を維持するために必要な同期からは分離してカプセル化します。

値を 1 に初期化されたセマフォーは、利用できるパーミットが最大で 1 個であるセマフォーとして使用されるため、相互排他ロックとして利用できます。これは一般には「2 進型セマフォー」と呼ばれます。利用可能なパーミットが 1 個か 0 個かの 2 つの状態しかないためです。このように使用される場合、多くの Lock 実装とは異なり、2 進型セマフォーは、「ロック」を所有者以外のスレッドで解放できるという特性を持ちます (セマフォーには所有権の概念がないため)。これは、デッドロックの回復のような特殊なコンテキストで便利です。

このクラスのコンストラクタは、オプションの「公平性」パラメータを受け入れます。false に設定すると、このクラスはスレッドがパーミットを取得する順序について保証しません。特に、「割り込み」(barging) が許可されています。つまり、acquire() を呼び出すスレッドに、待機していたスレッドよりも先にパーミットを割り当てることが可能です。論理的には、新しいスレッドが待機中のスレッドのキューの先頭に配置されることになります。公平性が true に設定されると、セマフォーは、acquire メソッドを呼び出すスレッドが、呼び出しが処理された順 (先入れ先出し、FIFO) でパーミットを取得するように選択されることを保証します。FIFO 順序付けは、必然的にこれらのメソッド内の特定の内部実行ポイントに適用されます。そのため、あるスレッドが別のスレッドより先に acquire を呼び出すが、そのスレッドよりあとに順序付けポイントに達する場合があります。また、メソッドからの復帰時にも同様のことが起こる可能性があります。また、時間指定のない tryAcquire メソッドは公平性設定を尊重せず、受け入れませんが、利用可能なパーミットは取得します。

通常、リソースアクセスを制御するために使用されるセマフォーは、リソースへのアクセスができないスレッドがないよう、公平に初期化される必要があります。ほかの種類の同期制御にセマフォーを使用する場合は、公平性を考慮するよりも不公平な順序付けによるスループットの利点のほうがしばしば重要になります。

このクラスには、同時に複数のパーミットを 取得 および 解放 するための簡易メソッドもあります。公平性を true に設定せずにこれらのメソッドを使用すると、無期限に延期される危険が増すことに注意してください。

メモリー整合性効果:release() などの「解放」メソッドを呼び出す前のスレッド内のアクションは、別のスレッドで acquire() などの正常終了した「取得」メソッドに続くアクションよりも「前に発生」します。

導入されたバージョン:
1.5
関連項目:
直列化された形式

コンストラクタの概要
Semaphore(int permits)
          指定された数のパーミットと不公平な公平性設定を使用して、Semaphore を作成します。
Semaphore(int permits, boolean fair)
          指定された数のパーミットと指定された公平性設定を使用して、Semaphore を作成します。
 
メソッドの概要
 void acquire()
          このセマフォーからパーミットを取得します。
 void acquire(int permits)
          このセマフォーから指定された数のパーミットを取得します。
 void acquireUninterruptibly()
          このセマフォーからパーミットを取得します。
 void acquireUninterruptibly(int permits)
          このセマフォーから指定された数のパーミットを取得します。
 int availablePermits()
          このセマフォーで現在利用可能なパーミットの数を返します。
 int drainPermits()
          すぐに利用可能なすべてのパーミットを取得して返します。
protected  Collection<Thread> getQueuedThreads()
          パーミットの取得を待機しているスレッドを含むコレクションを返します。
 int getQueueLength()
          パーミットの取得を待機しているスレッドの推定数を返します。
 boolean hasQueuedThreads()
          パーミットの取得を待機中のスレッドが存在するかどうかを照会します。
 boolean isFair()
          このセマフォーで公平性が true に設定されている場合は true を返します。
protected  void reducePermits(int reduction)
          指定された reduction の数だけ利用可能なパーミットの数を減らします。
 void release()
          パーミットを解放し、セマフォーに戻します。
 void release(int permits)
          指定された数のパーミットを解放し、セマフォーに戻します。
 String toString()
          セマフォーおよびその状態を識別する文字列を返します。
 boolean tryAcquire()
          パーミットが呼び出し時に利用可能な場合に限り、このセマフォーからパーミットを取得します。
 boolean tryAcquire(int permits)
          指定された数のパーミットが呼び出し時に利用可能な場合に限り、それらすべてのパーミットを取得します。
 boolean tryAcquire(int permits, long timeout, TimeUnit unit)
          指定された待機時間内で指定された数のパーミットが利用可能であり、現在のスレッドで 割り込み が発生していない場合に、このセマフォーから指定された数のパーミットを取得します。
 boolean tryAcquire(long timeout, TimeUnit unit)
          指定された待機時間内でパーミットが利用可能になり、現在のスレッドで 割り込み が発生していない場合に、このセマフォーからパーミットを取得します。
 
クラス java.lang.Object から継承されたメソッド
clone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait
 

コンストラクタの詳細

Semaphore

public Semaphore(int permits)
指定された数のパーミットと不公平な公平性設定を使用して、Semaphore を作成します。

パラメータ:
permits - 利用可能なパーミットの初期の数。 この値は負にすることも可能で、その場合は取得メソッドが許可を受け取る前に解放が発生する必要がある

Semaphore

public Semaphore(int permits,
                 boolean fair)
指定された数のパーミットと指定された公平性設定を使用して、Semaphore を作成します。

パラメータ:
permits - 利用可能なパーミットの初期の数。 この値は負にすることも可能で、その場合は取得メソッドが許可を受け取る前に解放が発生する必要がある
fair - このセマフォーが競合時にパーミットの許可を先入れ先出しで保証する場合は true、そうでない場合は false
メソッドの詳細

acquire

public void acquire()
             throws InterruptedException
このセマフォーからパーミットを取得します。パーミットが利用可能になるか、またはスレッドが 割り込み されるまでブロックします。

パーミットが利用可能な場合はパーミットを取得してすぐに復帰するため、利用可能なパーミットの数は 1 つずつ減ります。

パーミットが利用可能でない場合、現在のスレッドはスレッドのスケジューリングに関して無効になり、次の 2 つのいずれかが起きるまで待機します。

現在のスレッドで、

InterruptedException がスローされ、現在のスレッドの割り込みステータスがクリアされます。

例外:
InterruptedException - 現在のスレッドで割り込みが発生した場合

acquireUninterruptibly

public void acquireUninterruptibly()
このセマフォーからパーミットを取得します。パーミットが利用可能になるまでブロックします。

パーミットが利用可能な場合はパーミットを取得してすぐに復帰するため、利用可能なパーミットの数は 1 つずつ減ります。

パーミットが利用可能でない場合、現在のスレッドはスレッドのスケジューリングに関して無効になり、別のスレッドがこのセマフォーに対して release() メソッドを呼び出し、現在のスレッドが次にパーミットを割り当てられるスレッドになるまで、現在のスレッドは待機します。

パーミットの待機中に現在のスレッドが 割り込み されると、待機は続行しますが、スレッドにパーミットが割り当てられるタイミングは、割り込みが発生しなかった場合にパーミットを受け取るはずのタイミングとは異なることがあります。スレッドがこのメソッドから復帰すると、その割り込み状態が設定されます。


tryAcquire

public boolean tryAcquire()
パーミットが呼び出し時に利用可能な場合に限り、このセマフォーからパーミットを取得します。

パーミットが利用可能な場合はパーミットを取得して値 true ですぐに復帰するため、利用可能なパーミットの数は 1 つずつ減ります。

パーミットが利用可能でない場合、このメソッドは値 false ですぐに復帰します。

このセマフォーが公平順序付けポリシーを使用するように設定されている場合でも、パーミットが使用可能であれば、ほかのスレッドが現在待機しているかどうかに関係なく、tryAcquire() の呼び出しですぐにパーミットを取得します。この「割り込み」(barging) 動作により公平性が失われるとは言え、これは特定の状況下で有用です。公平性設定を尊重する場合は、ほぼ等価な tryAcquire(0, TimeUnit.SECONDS) を使用します (これも割り込みを検出する)。

戻り値:
パーミットが取得された場合は true、そうでない場合は false

tryAcquire

public boolean tryAcquire(long timeout,
                          TimeUnit unit)
                   throws InterruptedException
指定された待機時間内でパーミットが利用可能になり、現在のスレッドで 割り込み が発生していない場合に、このセマフォーからパーミットを取得します。

パーミットが利用可能な場合はパーミットを取得して値 true ですぐに復帰するため、利用可能なパーミットの数は 1 つずつ減ります。

パーミットが利用可能でない場合、現在のスレッドはスレッドのスケジューリングに関して無効になり、次の 3 つのいずれかが起きるまで待機します。

パーミットが取得されると、true が返されます。

現在のスレッドで、

InterruptedException がスローされ、現在のスレッドの割り込みステータスがクリアされます。

指定された待機時間が経過すると、値 false が返されます。時間がゼロまたはそれより小さい場合、メソッドは待機しません。

パラメータ:
timeout - パーミットの最長待機時間
unit - timeout 引数の時間単位
戻り値:
パーミットが取得された場合は true、パーミットが取得される前に待機時間が経過した場合は false
例外:
InterruptedException - 現在のスレッドで割り込みが発生した場合

release

public void release()
パーミットを解放し、セマフォーに戻します。

パーミットを解放すると、利用可能なパーミットの数が 1 つずつ増えます。いくつかのスレッドがパーミットを取得しようと試みている場合は、その中の 1 つのスレッドが選択され、解放されたばかりのパーミットが与えられます。そのスレッドは、スレッドのスケジューリングに関して (ふたたび) 有効になります。

パーミットを解放するスレッドは、acquire() の呼び出しでそのパーミットを取得している必要はありません。セマフォーの適切な使用法は、アプリケーションでのプログラミング規約で確立されます。


acquire

public void acquire(int permits)
             throws InterruptedException
このセマフォーから指定された数のパーミットを取得します。すべてのパーミットが利用可能になるか、またはスレッドが 割り込み されるまでブロックします。

指定された数のパーミットが利用可能な場合はパーミットを取得してすぐに復帰するため、利用可能なパーミットの数は指定された数ずつ減ります。

十分な数のパーミットが利用可能でない場合、現在のスレッドはスレッドのスケジューリングに関して無効になり、次の 2 つのいずれかが起きるまで待機します。

現在のスレッドで、

InterruptedException がスローされ、現在のスレッドの割り込みステータスがクリアされます。このスレッドに割り当てられるはずだったすべてのパーミットは、release() の呼び出しでパーミットが利用可能になったかのように、パーミットの取得を試みる別のスレッドに割り当てられます。

パラメータ:
permits - 取得するパーミットの数
例外:
InterruptedException - 現在のスレッドで割り込みが発生した場合
IllegalArgumentException - permits が負の値の場合

acquireUninterruptibly

public void acquireUninterruptibly(int permits)
このセマフォーから指定された数のパーミットを取得します。すべてのパーミットが利用可能になるまでブロックします。

指定された数のパーミットが利用可能な場合はパーミットを取得してすぐに復帰するため、利用可能なパーミットの数は指定された数ずつ減ります。

十分な数のパーミットが利用可能でない場合、現在のスレッドはスレッドのスケジューリングに関して無効になり、別のスレッドがこのセマフォーに対して release メソッドのいずれかを呼び出し、現在のスレッドが次にパーミットを割り当てられるスレッドになり、利用可能なパーミットの数がこの要求を満たすまで、現在のスレッドは待機します。

現在のスレッドがパーミットの待機中に 割り込まれた 場合、待機を続行します。キュー内での現在のスレッドの位置には影響ありません。スレッドがこのメソッドから復帰すると、その割り込み状態が設定されます。

パラメータ:
permits - 取得するパーミットの数
例外:
IllegalArgumentException - permits が負の値の場合

tryAcquire

public boolean tryAcquire(int permits)
指定された数のパーミットが呼び出し時に利用可能な場合に限り、それらすべてのパーミットを取得します。

指定された数のパーミットが利用可能な場合はパーミットを取得して値 true ですぐに復帰するため、利用可能なパーミットの数は指定された数ずつ減ります。

十分な数のパーミットが利用可能でない場合、このメソッドは値 false ですぐに復帰し、利用可能なパーミットの数は変化しません。

このセマフォーが公平順序付けポリシーを使用するように設定されている場合でも、パーミットが使用可能であれば、ほかのスレッドが現在待機しているかどうかに関係なく、tryAcquire() の呼び出しですぐにパーミットを取得します。この「割り込み」(barging) 動作により公平性が失われるとは言え、これは特定の状況下で有用です。公平性設定を尊重する場合は、ほぼ等価な tryAcquire(permits, 0, TimeUnit.SECONDS) を使用します (これも割り込みを検出する)。

パラメータ:
permits - 取得するパーミットの数
戻り値:
パーミットが取得された場合は true、そうでない場合は false
例外:
IllegalArgumentException - permits が負の値の場合

tryAcquire

public boolean tryAcquire(int permits,
                          long timeout,
                          TimeUnit unit)
                   throws InterruptedException
指定された待機時間内で指定された数のパーミットが利用可能であり、現在のスレッドで 割り込み が発生していない場合に、このセマフォーから指定された数のパーミットを取得します。

指定された数のパーミットが利用可能な場合はパーミットを取得して値 true ですぐに復帰するため、利用可能なパーミットの数は指定された数ずつ減ります。

十分な数のパーミットが利用可能でない場合、現在のスレッドはスレッドのスケジューリングに関して無効になり、次の 3 つのいずれかが起きるまで待機します。

パーミットが取得されると、true が返されます。

現在のスレッドで、

InterruptedException がスローされ、現在のスレッドの割り込みステータスがクリアされます。このスレッドに割り当てられるはずだったすべてのパーミットは、release() の呼び出しでパーミットが利用可能になったかのように、パーミットの取得を試みる別のスレッドに割り当てられます。

指定された待機時間が経過すると、値 false が返されます。時間がゼロまたはそれより小さい場合、メソッドは待機しません。このスレッドに割り当てられるはずだったすべてのパーミットは、release() の呼び出しでパーミットが利用可能になったかのように、パーミットの取得を試みる別のスレッドに割り当てられます。

パラメータ:
permits - 取得するパーミットの数
timeout - パーミットの最長待機時間
unit - timeout 引数の時間単位
戻り値:
すべてのパーミットが取得された場合は true、すべてのパーミットが取得される前に待機時間が経過した場合は false
例外:
InterruptedException - 現在のスレッドで割り込みが発生した場合
IllegalArgumentException - permits が負の値の場合

release

public void release(int permits)
指定された数のパーミットを解放し、セマフォーに戻します。

指定された数のパーミットを解放すると、利用可能なパーミットの数がその分増えます。いくつかのスレッドがパーミットを取得しようと試みている場合、その中の 1 つのスレッドが選択されて、解放されたばかりのパーミットが与えられます。利用可能なパーミットの数がそのスレッドの要求を満たす場合、そのスレッドはスレッドのスケジューリングに関して (ふたたび) 有効になります。そうでない場合、十分なパーミットが利用可能になるまでスレッドは待機します。このスレッドの要求を満たしたあとも引き続きパーミットが利用可能な場合、それらのパーミットはパーミットを取得しようとしている別のスレッドに割り当てられます。

パーミットを解放するスレッドは、acquire の呼び出しでそのパーミットを取得している必要はありません。セマフォーの適切な使用法は、アプリケーションでのプログラミング規約で確立されます。

パラメータ:
permits - 解放するパーミットの数
例外:
IllegalArgumentException - permits が負の値の場合

availablePermits

public int availablePermits()
このセマフォーで現在利用可能なパーミットの数を返します。

通常、このメソッドはデバッグとテストの場合に使用します。

戻り値:
このセマフォーで利用可能なパーミットの数

drainPermits

public int drainPermits()
すぐに利用可能なすべてのパーミットを取得して返します。

戻り値:
取得されたパーミットの数

reducePermits

protected void reducePermits(int reduction)
指定された reduction の数だけ利用可能なパーミットの数を減らします。このメソッドは、利用不可能になるリソースを追跡するためにセマフォーを使用するサブクラスで有用です。パーミットが利用可能になるまでブロックして待機しない点で、このメソッドは acquire と異なります。

パラメータ:
reduction - 削除するパーミットの数
例外:
IllegalArgumentException - reduction が負の値の場合

isFair

public boolean isFair()
このセマフォーで公平性が true に設定されている場合は true を返します。

戻り値:
このセマフォーで公平性が true に設定されている場合は true

hasQueuedThreads

public final boolean hasQueuedThreads()
パーミットの取得を待機中のスレッドが存在するかどうかを照会します。取り消しはいつでも発生する可能性があるため、true が返されても、ほかのいずれかのスレッドがパーミットを取得することは保証されていません。このメソッドは、主にシステム状態の監視に使用する目的で設計されています。

戻り値:
ロックの取得を待機中のほかのスレッドが存在する可能性がある場合は true

getQueueLength

public final int getQueueLength()
パーミットの取得を待機しているスレッドの推定数を返します。このメソッドが内部のデータ構造をトラバースしている間にも、スレッド数が動的に変化する場合があるため、この値は推定に過ぎません。このメソッドは、同期の制御用としてではなく、システム状態の監視用として設計されています。

戻り値:
このロックを待機しているスレッドの推定数

getQueuedThreads

protected Collection<Thread> getQueuedThreads()
パーミットの取得を待機しているスレッドを含むコレクションを返します。実際のスレッドセットは、結果の構築中にも動的に変化する可能性があるため、返されるコレクションは最善の努力を払った上での推定に過ぎません。返されるコレクションの要素には、特定の順序は存在しません。このメソッドは、より包括的な監視機能を提供するサブクラスの構築を容易にする目的で設計されています。

戻り値:
スレッドのコレクション

toString

public String toString()
セマフォーおよびその状態を識別する文字列を返します。状態は括弧で囲まれ、文字列 "Permits =" に続いてパーミットの数が含まれます。

オーバーライド:
クラス Object 内の toString
戻り値:
このセマフォーおよびその状態を識別する文字列

JavaTM Platform
Standard Ed. 6

バグの報告と機能のリクエスト
さらに詳しい API リファレンスおよび開発者ドキュメントについては、Java SE 開発者用ドキュメントを参照してください。開発者向けの詳細な解説、概念の概要、用語の定義、バグの回避策、およびコード実例が含まれています。

Copyright 2006 Sun Microsystems, Inc. All rights reserved. Use is subject to license terms. Documentation Redistribution Policy も参照してください。