[解決済み】javaでwait()とnotify()を使った簡単なシナリオ
質問
簡単なシナリオ、つまりチュートリアルを用意して、Queueをどのように使うか具体的に教えてください。
どのように解決するのですか?
その
wait()
と
notify()
メソッドは、特定の条件が満たされるまでスレッドをブロックするためのメカニズムを提供するように設計されています。このメソッドでは、固定サイズの要素を保存するブロッキングキューを実装することを想定しています。
まず最初にしなければならないことは、メソッドに待機させたい条件を特定することです。この場合
put()
メソッドはストアに空き領域ができるまでブロックするようにし
take()
メソッドは、返すべき要素があるまでブロックします。
public class BlockingQueue<T> {
private Queue<T> queue = new LinkedList<T>();
private int capacity;
public BlockingQueue(int capacity) {
this.capacity = capacity;
}
public synchronized void put(T element) throws InterruptedException {
while(queue.size() == capacity) {
wait();
}
queue.add(element);
notify(); // notifyAll() for multiple producer/consumer threads
}
public synchronized T take() throws InterruptedException {
while(queue.isEmpty()) {
wait();
}
T item = queue.remove();
notify(); // notifyAll() for multiple producer/consumer threads
return item;
}
}
waitとnotifyのメカニズムを使用しなければならない方法について、いくつか注意すべき点があります。
第一に、すべての呼び出された
wait()
または
notify()
が同期されたコード領域内にある場合 (
wait()
と
notify()
の呼び出しが同じオブジェクト上で同期化されていることを意味します)。この理由は(標準的なスレッドセーフの懸念以外に)、ミスシグナルと呼ばれるものによるものです。
この例として、あるスレッドが
put()
キューが満杯になると、その状態をチェックし、キューが満杯であることを確認します。 しかし、ブロックする前に、別のスレッドがスケジュールされます。この2番目のスレッドは、次に
take()
キューから要素を取得し、待機中のスレッドにキューが満杯でなくなったことを通知します。しかし、最初のスレッドはすでにその状態をチェックしているので、単に
wait()
を実行し、再スケジュールされた後、たとえそれが進展していたとしても。
共有オブジェクト上で同期をとることで、この問題が発生しないように、2番目のスレッドの
take()
の呼び出しは、最初のスレッドが実際にブロックされるまで、進行することができません。
次に、スプリアスウェイクアップと呼ばれる問題のために、チェックする条件をif文ではなくwhileループに入れる必要があります。この場合、待機中のスレッドが
notify()
が呼び出されます。このチェックを while ループに入れることで、もし偽のウェイクアップが発生した場合、条件が再チェックされ、スレッドから
wait()
を再び使用する。
他の回答にもあるように、Java 1.5では新しい並行処理ライブラリ(
java.util.concurrent
パッケージ)で、wait/notify機構をより高度に抽象化するように設計されています。これらの新機能を使えば、元の例を次のように書き換えることができます。
public class BlockingQueue<T> {
private Queue<T> queue = new LinkedList<T>();
private int capacity;
private Lock lock = new ReentrantLock();
private Condition notFull = lock.newCondition();
private Condition notEmpty = lock.newCondition();
public BlockingQueue(int capacity) {
this.capacity = capacity;
}
public void put(T element) throws InterruptedException {
lock.lock();
try {
while(queue.size() == capacity) {
notFull.await();
}
queue.add(element);
notEmpty.signal();
} finally {
lock.unlock();
}
}
public T take() throws InterruptedException {
lock.lock();
try {
while(queue.isEmpty()) {
notEmpty.await();
}
T item = queue.remove();
notFull.signal();
return item;
} finally {
lock.unlock();
}
}
}
もちろん、実際にブロッキングキューが必要な場合は、その実装を使用する必要があります。 BlockingQueue インターフェイスを使用します。
また、このようなものには、ぜひ Java並行処理の実践 並行処理に関連する問題と解決策について知りたいことがすべて網羅されているからです。
関連
-
Eclipseでプロジェクトエクスプローラービューとパッケージエクスプローラービューを使う
-
[解決済み] JavaでInputStreamを読み込んでStringに変換するにはどうすればよいですか?
-
[解決済み] JavaにおけるHashMapとHashtableの違いは何ですか?
-
[解決済み] Javaにおけるpublic、protected、package-private、privateの違いは何ですか?
-
[解決済み] JavaでArrayListではなくLinkedListを使用するのはいつですか?
-
[解決済み] B "の印刷が "#"の印刷より劇的に遅いのはなぜですか?
-
[解決済み] java.net.URLConnectionを使用してHTTPリクエストを発生させ処理する方法
-
[解決済み] Javaでネストされたループから抜け出すには?
-
[解決済み] なぜゲッターとセッター/アクセッサーを使うのですか?
-
[解決済み】Android UserManager.isUserAGoat()の正しい使用例?)
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
Java のエラーです。未解決のコンパイル問題 解決方法
-
jd-gui Java Exceptionが発生しました。
-
Enumとの組み合わせでswitchの使い方を一度覚えるために必要な定数式
-
JDKの設定時にjava.dllが見つからない、java SE Runtime Environmentが見つからない問題が発生しました。
-
リソースの読み込みに失敗しました。サーバーはステータス500(内部サーバーエラー)で応答しました。
-
[オリジナル】java学習ノート【II】よくあるエラー クラスパス上のクラスファイルが見つからない、またはアクセスできない場合
-
mavenプロジェクトのテストエラー java.lang.ClassNotFoundException: org.glassfish.jersey.client.ClientConfig の問題を解決する。
-
java.lang.NoClassDefFoundError: org.apache.jasper.el.ELContextImpl クラスを初期化できませんでした。
-
Error: java.lang.NoClassDefFoundError: クラス XXXX を初期化できませんでした
-
[解決済み] Java:notify()対notifyAll()の繰り返し