1

Javaでは、以下のコードを使用して単純なwaitおよびnotifyAll()メソッドを使用してプロデューサーとコンシューマーの実装を記述しようとしていました。数秒間実行され、後でハングします。これを解決する方法を考えてみてください。

import java.util.ArrayDeque;
import java.util.Queue;

public class Prod_consumer {
    static Queue<String> q = new ArrayDeque(10);

    static class Producer implements Runnable {
        public void run() {
            while (true) {
                if (q.size() == 10) {
                    synchronized (q) {
                        try {
                            System.out.println("Q is full so waiting");
                            q.wait();
                        } catch (InterruptedException ex) {
                            ex.printStackTrace();
                        }
                    }
                }
                synchronized (q) {
                    String st = System.currentTimeMillis() + "";
                    q.add(st);
                    q.notifyAll();
                }
            }
        }

    }

    static class Consumer implements Runnable {
        public void run() {
            while (true) {
                if (q.isEmpty()) {
                    synchronized(q) {
                        try {
                            System.out.println("Q is empty so waiting ");
                            q.wait();
                        }catch(InterruptedException ie) {
                            ie.printStackTrace();
                        }
                    }
                }
                synchronized(q) {
                    System.out.println(q.remove());
                    q.notifyAll();
                }

            }

        }
    }

    public static void main(String args[]) {
        Thread consumer = new Thread(new Consumer());
        Thread consumer2 = new Thread(new Consumer());
        Thread producer = new Thread(new Producer());

        producer.start();
        consumer.start();
        consumer2.start();

    }

}
4

4 に答える 4

2

あなたのProducerコードは疑わしいようです。キューのサイズが 10 未満になるまで待ってから、次の要素を追加します。ただし、現在のロジックでは、理由に関係なく、通知まで待機し、キューが容量を超えているかどうかを確認せず、キューのロックを解放します。次に、キューを再度ロックして項目を追加します (別のスレッドが何かをキューに入れたかどうかに関係なく)。

このコードをお勧めします:

static class Producer implements Runnable {
    public void run() {
        while (true) {
            synchronized (q) {
                if (q.size() < 10) {
                    String st = System.currentTimeMillis() + "";
                    q.add(st);
                    q.notifyAll();
                } else {
                    try {
                        System.out.println("Q is full so waiting");
                        q.wait();
                    } catch (InterruptedException ex) {
                        ex.printStackTrace();
                    }
                }
            }
        }
    }
}

クラスにも同様の問題がありConsumerます。私はこれを提案します:

static class Consumer implements Runnable {
    public void run() {
        while (true) {
            synchronized (q) {
                if (q.isEmpty()) {
                    try {
                        System.out.println("Q is empty so waiting ");
                        q.wait();
                    }catch(InterruptedException ie) {
                        ie.printStackTrace();
                    }
                } else {
                    System.out.println(q.remove());
                    q.notifyAll();
                }
            }
        }
    }
}

どちらの場合も、続行してもよいかどうかをチェックするコードとメソッドの実際の処理の間でロックが維持されることに注意してください。

于 2013-07-19T01:53:28.340 に答える
1

共有メモリに対するすべての操作は、マルチスレッド アクセスから保護する必要があります。現在の実装では、キュー チェックの非同期状態が原因でデッドロックが発生しています。そのコードを Promela で簡単にモデル化して、デッドロック シナリオを取得できるはずです。ただし、condition_variables (同期セクション) にはカウント セマンティックがないことに注意する必要があります。そのため、スレッドが待機状態に達する前に横取りされ、その間に別のスレッドが notifyAll() 関数を呼び出した場合、それ以降の横取りされたスレッドには適用されません。コントロールを取り戻します。解決策は非常に簡単です。

...
while (true)
{
    synchronized (q)
    {
        if (q.size() == 10)
...
while (true)
{
    synchronized(q)
    {
        if (q.isEmpty())
...
于 2013-07-19T02:03:18.547 に答える
0

同期されたキューに触れるすべてのコードをラップする必要があります。例えば

if (q.size() == 10) {
    synchronized (q) {

if ステートメントが評価された後、キューのサイズが変わる可能性があります。順番を入れ替えたほうがいいです。

コンシューマーにも同じ問題があります

于 2013-07-19T01:52:50.273 に答える