|
JavaTM Platform Standard Ed. 6 |
|||||||||
前のクラス 次のクラス | フレームあり フレームなし | |||||||||
概要: 入れ子 | フィールド | コンストラクタ | メソッド | 詳細: フィールド | コンストラクタ | メソッド |
java.lang.Object java.util.concurrent.Semaphore
public class Semaphore
計数セマフォーです。概念的に、セマフォーはパーミットのセットを維持します。各 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()
などの正常終了した「取得」メソッドに続くアクションよりも「前に発生」します。
コンストラクタの概要 | |
---|---|
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 |
コンストラクタの詳細 |
---|
public Semaphore(int permits)
Semaphore
を作成します。
permits
- 利用可能なパーミットの初期の数。この値は負にすることも可能で、その場合は取得メソッドが許可を受け取る前に解放が発生する必要があるpublic Semaphore(int permits, boolean fair)
Semaphore
を作成します。
permits
- 利用可能なパーミットの初期の数。この値は負にすることも可能で、その場合は取得メソッドが許可を受け取る前に解放が発生する必要があるfair
- このセマフォーが競合時にパーミットの許可を先入れ先出しで保証する場合は true
、そうでない場合は false
メソッドの詳細 |
---|
public void acquire() throws InterruptedException
パーミットが利用可能な場合はパーミットを取得してすぐに復帰するため、利用可能なパーミットの数は 1 つずつ減ります。
パーミットが利用可能でない場合、現在のスレッドはスレッドのスケジューリングに関して無効になり、次の 2 つのいずれかが起きるまで待機します。
現在のスレッドで、
InterruptedException
がスローされ、現在のスレッドの割り込みステータスがクリアされます。
InterruptedException
- 現在のスレッドで割り込みが発生した場合public void acquireUninterruptibly()
パーミットが利用可能な場合はパーミットを取得してすぐに復帰するため、利用可能なパーミットの数は 1 つずつ減ります。
パーミットが利用可能でない場合、現在のスレッドはスレッドのスケジューリングに関して無効になり、別のスレッドがこのセマフォーに対して release()
メソッドを呼び出し、現在のスレッドが次にパーミットを割り当てられるスレッドになるまで、現在のスレッドは待機します。
パーミットの待機中に現在のスレッドが 割り込み されると、待機は続行しますが、スレッドにパーミットが割り当てられるタイミングは、割り込みが発生しなかった場合にパーミットを受け取るはずのタイミングとは異なることがあります。スレッドがこのメソッドから復帰すると、その割り込み状態が設定されます。
public boolean tryAcquire()
パーミットが利用可能な場合はパーミットを取得して値 true
ですぐに復帰するため、利用可能なパーミットの数は 1 つずつ減ります。
パーミットが利用可能でない場合、このメソッドは値 false
ですぐに復帰します。
このセマフォーが公平順序付けポリシーを使用するように設定されている場合でも、パーミットが使用可能であれば、ほかのスレッドが現在待機しているかどうかに関係なく、tryAcquire()
の呼び出しですぐにパーミットを取得します。この「割り込み」(barging) 動作により公平性が失われるとは言え、これは特定の状況下で有用です。公平性設定を尊重する場合は、ほぼ等価な tryAcquire(0, TimeUnit.SECONDS)
を使用します (これも割り込みを検出する)。
true
、そうでない場合は false
public boolean tryAcquire(long timeout, TimeUnit unit) throws InterruptedException
パーミットが利用可能な場合はパーミットを取得して値 true
ですぐに復帰するため、利用可能なパーミットの数は 1 つずつ減ります。
パーミットが利用可能でない場合、現在のスレッドはスレッドのスケジューリングに関して無効になり、次の 3 つのいずれかが起きるまで待機します。
release()
メソッドを呼び出し、現在のスレッドが次にパーミットを割り当てられるスレッドになる。
パーミットが取得されると、true
が返されます。
現在のスレッドで、
InterruptedException
がスローされ、現在のスレッドの割り込みステータスがクリアされます。
指定された待機時間が経過すると、値 false
が返されます。時間がゼロまたはそれより小さい場合、メソッドは待機しません。
timeout
- パーミットの最長待機時間unit
- timeout
引数の時間単位
true
、パーミットが取得される前に待機時間が経過した場合は false
InterruptedException
- 現在のスレッドで割り込みが発生した場合public void release()
パーミットを解放すると、利用可能なパーミットの数が 1 つずつ増えます。いくつかのスレッドがパーミットを取得しようと試みている場合は、その中の 1 つのスレッドが選択され、解放されたばかりのパーミットが与えられます。そのスレッドは、スレッドのスケジューリングに関して (ふたたび) 有効になります。
パーミットを解放するスレッドは、acquire()
の呼び出しでそのパーミットを取得している必要はありません。セマフォーの適切な使用法は、アプリケーションでのプログラミング規約で確立されます。
public void acquire(int permits) throws InterruptedException
指定された数のパーミットが利用可能な場合はパーミットを取得してすぐに復帰するため、利用可能なパーミットの数は指定された数ずつ減ります。
十分な数のパーミットが利用可能でない場合、現在のスレッドはスレッドのスケジューリングに関して無効になり、次の 2 つのいずれかが起きるまで待機します。
release
メソッドのいずれかを呼び出し、現在のスレッドが次にパーミットを割り当てられるスレッドになり、利用可能なパーミットの数がこの要求を満たす。
現在のスレッドで、
InterruptedException
がスローされ、現在のスレッドの割り込みステータスがクリアされます。このスレッドに割り当てられるはずだったすべてのパーミットは、release()
の呼び出しでパーミットが利用可能になったかのように、パーミットの取得を試みる別のスレッドに割り当てられます。
permits
- 取得するパーミットの数
InterruptedException
- 現在のスレッドで割り込みが発生した場合
IllegalArgumentException
- permits
が負の値の場合public void acquireUninterruptibly(int permits)
指定された数のパーミットが利用可能な場合はパーミットを取得してすぐに復帰するため、利用可能なパーミットの数は指定された数ずつ減ります。
十分な数のパーミットが利用可能でない場合、現在のスレッドはスレッドのスケジューリングに関して無効になり、別のスレッドがこのセマフォーに対して release
メソッドのいずれかを呼び出し、現在のスレッドが次にパーミットを割り当てられるスレッドになり、利用可能なパーミットの数がこの要求を満たすまで、現在のスレッドは待機します。
現在のスレッドがパーミットの待機中に 割り込まれた
場合、待機を続行します。キュー内での現在のスレッドの位置には影響ありません。スレッドがこのメソッドから復帰すると、その割り込み状態が設定されます。
permits
- 取得するパーミットの数
IllegalArgumentException
- permits
が負の値の場合public boolean tryAcquire(int permits)
指定された数のパーミットが利用可能な場合はパーミットを取得して値 true
ですぐに復帰するため、利用可能なパーミットの数は指定された数ずつ減ります。
十分な数のパーミットが利用可能でない場合、このメソッドは値 false
ですぐに復帰し、利用可能なパーミットの数は変化しません。
このセマフォーが公平順序付けポリシーを使用するように設定されている場合でも、パーミットが使用可能であれば、ほかのスレッドが現在待機しているかどうかに関係なく、tryAcquire()
の呼び出しですぐにパーミットを取得します。この「割り込み」(barging) 動作により公平性が失われるとは言え、これは特定の状況下で有用です。公平性設定を尊重する場合は、ほぼ等価な tryAcquire(permits, 0, TimeUnit.SECONDS)
を使用します (これも割り込みを検出する)。
permits
- 取得するパーミットの数
true
、そうでない場合は false
IllegalArgumentException
- permits
が負の値の場合public boolean tryAcquire(int permits, long timeout, TimeUnit unit) throws InterruptedException
指定された数のパーミットが利用可能な場合はパーミットを取得して値 true
ですぐに復帰するため、利用可能なパーミットの数は指定された数ずつ減ります。
十分な数のパーミットが利用可能でない場合、現在のスレッドはスレッドのスケジューリングに関して無効になり、次の 3 つのいずれかが起きるまで待機します。
release
メソッドのいずれかを呼び出し、現在のスレッドが次にパーミットを割り当てられるスレッドになり、利用可能なパーミットの数がこの要求を満たす。
パーミットが取得されると、true
が返されます。
現在のスレッドで、
InterruptedException
がスローされ、現在のスレッドの割り込みステータスがクリアされます。このスレッドに割り当てられるはずだったすべてのパーミットは、release()
の呼び出しでパーミットが利用可能になったかのように、パーミットの取得を試みる別のスレッドに割り当てられます。
指定された待機時間が経過すると、値 false
が返されます。時間がゼロまたはそれより小さい場合、メソッドは待機しません。このスレッドに割り当てられるはずだったすべてのパーミットは、release()
の呼び出しでパーミットが利用可能になったかのように、パーミットの取得を試みる別のスレッドに割り当てられます。
permits
- 取得するパーミットの数timeout
- パーミットの最長待機時間unit
- timeout
引数の時間単位
true
、すべてのパーミットが取得される前に待機時間が経過した場合は false
InterruptedException
- 現在のスレッドで割り込みが発生した場合
IllegalArgumentException
- permits
が負の値の場合public void release(int permits)
指定された数のパーミットを解放すると、利用可能なパーミットの数がその分増えます。いくつかのスレッドがパーミットを取得しようと試みている場合、その中の 1 つのスレッドが選択されて、解放されたばかりのパーミットが与えられます。利用可能なパーミットの数がそのスレッドの要求を満たす場合、そのスレッドはスレッドのスケジューリングに関して (ふたたび) 有効になります。そうでない場合、十分なパーミットが利用可能になるまでスレッドは待機します。このスレッドの要求を満たしたあとも引き続きパーミットが利用可能な場合、それらのパーミットはパーミットを取得しようとしている別のスレッドに割り当てられます。
パーミットを解放するスレッドは、acquire
の呼び出しでそのパーミットを取得している必要はありません。セマフォーの適切な使用法は、アプリケーションでのプログラミング規約で確立されます。
permits
- 解放するパーミットの数
IllegalArgumentException
- permits
が負の値の場合public int availablePermits()
通常、このメソッドはデバッグとテストの場合に使用します。
public int drainPermits()
protected void reducePermits(int reduction)
acquire
と異なります。
reduction
- 削除するパーミットの数
IllegalArgumentException
- reduction
が負の値の場合public boolean isFair()
true
を返します。
true
public final boolean hasQueuedThreads()
true
public final int getQueueLength()
protected Collection<Thread> getQueuedThreads()
public String toString()
"Permits ="
に続いてパーミットの数が含まれます。
Object
内の toString
|
JavaTM Platform Standard Ed. 6 |
|||||||||
前のクラス 次のクラス | フレームあり フレームなし | |||||||||
概要: 入れ子 | フィールド | コンストラクタ | メソッド | 詳細: フィールド | コンストラクタ | メソッド |
Copyright 2009 Sun Microsystems, Inc. All rights reserved. Use is subject to license terms. Documentation Redistribution Policy も参照してください。