4

Javaでマルチスレッドのwaitおよびnotifyメソッドを使用してプログラムを作成したいと考えています。
このプログラムにはスタックがあります (最大長 = 5)。プロデューサーは永久に番号を生成してスタックに入れ、コンシューマーはスタックからそれを選択します。

スタックがいっぱいの場合はプロデューサーが待機し、スタックが空の場合はコンシューマーが待機する必要があります。
問題は、一度だけ実行されることです。つまり、5 つの数値が生成されると停止しますが、実行メソッドを while(true) ブロックに入れてノンストップで実行できますが、実行されません。
これが私がこれまでに試したことです。
プロデューサー クラス:

package trail;
import java.util.Random;
import java.util.Stack;

public class Thread1 implements Runnable {
    int result;
    Random rand = new Random();
    Stack<Integer> A = new Stack<>();

    public Thread1(Stack<Integer> A) {
        this.A = A;
    }

    public synchronized void produce()
    {
        while (A.size() >= 5) {
            System.out.println("List is Full");
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        result = rand.nextInt(10);

        System.out.println(result + " produced ");
        A.push(result);
        System.out.println(A);

        this.notify();
    }

    @Override
    public void run() {
        System.out.println("Producer get started");

        try {
            Thread.sleep(10);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        while (true) {
            produce();
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

そして消費者:

package trail;

import java.util.Stack;

public class Thread2 implements Runnable {
    Stack<Integer> A = new Stack<>();

    public Thread2(Stack<Integer> A) {
        this.A = A;
    }

    public synchronized void consume() {
        while (A.isEmpty()) {
            System.err.println("List is empty" + A + A.size());
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.err.println(A.pop() + " Consumed " + A);
        this.notify();
    }

    @Override
    public void run() {
        System.out.println("New consumer get started");
        try {
            Thread.sleep(10);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        while (true) {
            consume();
        }
    }
}

ここに主な方法があります:

public static void main(String[] args) {

        Stack<Integer> stack = new Stack<>();

        Thread1 thread1 = new Thread1(stack);// p
        Thread2 thread2 = new Thread2(stack);// c
        Thread A = new Thread(thread1);
        Thread B = new Thread(thread2);
        Thread C = new Thread(thread2);
        A.start();

        B.start();
        C.start();     
    }
4

9 に答える 9

2

コンシューマーとプロデューサーは異なるオブジェクトで同期され、お互いをブロックしません。これが機能する場合、あえて言えば偶然です。

とを読んでjava.util.concurrent.BlockingQueueくださいjava.util.concurrent.ArrayBlockingQueue。これらは、このパターンを実装するためのよりモダンで簡単な方法を提供します。

http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/BlockingQueue.html

于 2013-08-13T10:37:26.890 に答える
2

現在混合されている3つのことを分離しようとすると、一般的に同期を理解して処理するのに適していると思います。

  1. 実際の仕事を行うタスク。クラスThread1&の名前Thread2は誤解を招きます。これらは Thread オブジェクトではありませんが、実際には、Threadオブジェクトに与える Runnable インターフェイスを実装するジョブまたはタスクです。

  2. メインで作成しているスレッドオブジェクト自体

  3. キュー、スタックなどで同期された操作/ロジックをカプセル化する共有オブジェクト。このオブジェクトはタスク間で共有されます。そして、この共有オブジェクト内で、(同期ブロックまたは同期メソッドのいずれかを使用して) 追加/削除操作を処理します。現在 (すでに指摘されているように)、同期はタスク自体で行われます (つまり、各タスクは独自のロックで待機して通知し、何も起こりません)。懸念事項を分離すると、つまり、1 つのクラスに 1 つのことを適切に行わせると、最終的にどこに問題があるかが明らかになります。

于 2013-08-13T11:44:29.687 に答える
0

このコード例を見てください:

import java.util.concurrent.*;
import java.util.Random;

public class ProducerConsumerMulti {
    public static void main(String args[]){
        BlockingQueue<Integer> sharedQueue = new LinkedBlockingQueue<Integer>();

        Thread prodThread  = new Thread(new Producer(sharedQueue,1));
        Thread consThread1 = new Thread(new Consumer(sharedQueue,1));
        Thread consThread2 = new Thread(new Consumer(sharedQueue,2));

        prodThread.start();
        consThread1.start();
        consThread2.start();
    } 
}
class Producer implements Runnable {
    private final BlockingQueue<Integer> sharedQueue;
    private int threadNo;
    private Random rng;
    public Producer(BlockingQueue<Integer> sharedQueue,int threadNo) {
        this.threadNo = threadNo;
        this.sharedQueue = sharedQueue;
        this.rng = new Random();
    }
    @Override
    public void run() {
        while(true){
            try {
                int number = rng.nextInt(100);
                System.out.println("Produced:" + number + ":by thread:"+ threadNo);
                sharedQueue.put(number);
                Thread.sleep(100);
            } catch (Exception err) {
                err.printStackTrace();
            }
        }
    }
}

class Consumer implements Runnable{
    private final BlockingQueue<Integer> sharedQueue;
    private int threadNo;
    public Consumer (BlockingQueue<Integer> sharedQueue,int threadNo) {
        this.sharedQueue = sharedQueue;
        this.threadNo = threadNo;
    }

    @Override
    public void run() {
        while(true){
            try {
                int num = sharedQueue.take();
                System.out.println("Consumed: "+ num + ":by thread:"+threadNo);
                Thread.sleep(100);
            } catch (Exception err) {
               err.printStackTrace();
            }
        }
    }   
}

ノート:

  1. 問題の説明に従って、 1つとProducer2つを開始しましたConsumers
  2. Producer無限ループで 0 から 100 までの乱数を生成します
  3. Consumerこれらの数値を無限ループで消費します
  4. 両方ともProducerConsumerロックフリーでスレッドセーフなLinkedBlockingQueueを共有します 。これはスレッドセーフです。これらの高度な並行構造を使用する場合は、wait() および notify() メソッドを削除できます。
于 2016-06-16T14:48:26.690 に答える
0

これは本当に簡単でした。 http://developer.android.com/reference/java/util/concurrent/BlockingQueue.html

于 2015-01-24T00:00:17.623 に答える
0

Java の素晴らしいjava.util.concurrentパッケージとそのクラスを使用できます。

を使用して、生産者と消費者の問題を簡単に実装できます BlockingQueueBlockingQueueは、要素を取得するときにキューが空でなくなるのを待機し、要素を格納するときにキューでスペースが使用可能になるのを待機する操作を既にサポートしています。

がなければBlockingQueue、プロデューサ側でデータをキューに入れるたびに、キューが満杯かどうかを確認する必要があり、満杯の場合はしばらく待ってから再度確認して続行します。同様に、コンシューマー側でも、キューが空かどうかを確認し、空の場合はしばらく待ってから再度確認して続行する必要があります。ただし、BlockingQueueProducer からデータを追加し、Consumer からデータをポーリングするだけで、追加のロジックを記述する必要はありません。

もっと読む 差出人:

http://javawithswaranga.blogspot.in/2012/05/solving-producer-consumer-problem-in.html

http://www.javajee.com/producer-consumer-problem-in-Java-using-blockingqueue

于 2013-08-13T11:56:42.430 に答える
-1

wait()notify()およびについて何かをスキップしたようですsynchronizedこの例を参照してください。役立つはずです。

于 2013-08-13T09:46:51.647 に答える