Java マルチスレッドを学習していますが、問題があります。セマフォを理解できません。この順序でスレッドを実行するにはどうすればよいですか? 例: on image1 : 5 番目のスレッドが実行を開始し、1 番目と 2 番目のスレッドの実行が終了します。
画像 2:
画像 1:
理解を深めるために画像をアップロードします。:))
Java マルチスレッドを学習していますが、問題があります。セマフォを理解できません。この順序でスレッドを実行するにはどうすればよいですか? 例: on image1 : 5 番目のスレッドが実行を開始し、1 番目と 2 番目のスレッドの実行が終了します。
画像 2:
画像 1:
理解を深めるために画像をアップロードします。:))
通常、Javaではミューテックス(モニターとも呼ばれます)を使用します。これにより、2つ以上のスレッドがそのミューテックスによって保護されたコード領域にアクセスできなくなります。
そのコード領域は、sychronized
ステートメントを使用して定義されます
sychronized(mutex) {
// mutual exclusive code begin
// ...
// ...
// mutual exclusive code end
}
ここで、mutexは次のように定義されます。
Object mutex = new Object();
タスクが開始されないようにするには、java.util.concurrencyパッケージで定義されているバリアなどの高度な技術が必要です。
しかし、最初にそのsynchronized
声明に満足してください。
Javaでマルチスレッドを頻繁に使用すると思われる場合は、以下をお読みください。
「実際のJava並行性」
Synchronized は、各スレッドが一度にそのメソッドまたはコードのその部分に入るために使用されます。あなたがしたい場合は
public class CountingSemaphore {
private int value = 0;
private int waitCount = 0;
private int notifyCount = 0;
public CountingSemaphore(int initial) {
if (initial > 0) {
value = initial;
}
}
public synchronized void waitForNotify() {
if (value <= waitCount) {
waitCount++;
try {
do {
wait();
} while (notifyCount == 0);
} catch (InterruptedException e) {
notify();
} finally {
waitCount--;
}
notifyCount--;
}
value--;
}
public synchronized void notifyToWakeup() {
value++;
if (waitCount > notifyCount) {
notifyCount++;
notify();
}
}
}
これは、カウンティング セマフォの実装です。カウンター変数「value」、「waitCount」、および「notifyCount」を維持します。これにより、値が waitCount よりも小さく、notifyCount が空の場合、スレッドは待機します。
Java カウント セマフォを使用できます。概念的には、セマフォは一連の許可を維持します。それぞれの acquire() は、必要に応じて許可が利用可能になるまでブロックし、それを取得します。各 release() は許可を追加し、ブロックしている取得者を解放する可能性があります。ただし、実際の許可オブジェクトは使用されません。Semaphore は、使用可能な数のカウントを保持し、それに応じて動作します。
セマフォは、いくつかの (物理的または論理的な) リソースにアクセスできるスレッドの数を制限するためによく使用されます。たとえば、セマフォを使用してアイテムのプールへのアクセスを制御するクラスを次に示します。
class Pool {
private static final 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 つの状態しかないため、より一般的にはバイナリ セマフォとして知られています。このように使用すると、バイナリ セマフォには、(多くの Lock 実装とは異なり) 所有者以外のスレッドが "ロック" を解放できるというプロパティがあります (セマフォには所有権の概念がないため)。これは、デッドロック回復などの特殊なコンテキストで役立ちます。