質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

87.80%

Java スレッド同士の待ち合わせについて

受付中

回答 1

投稿

  • 評価
  • クリップ 0
  • VIEW 2,130

score 15

前提・実現したいこと

入門書を参考にしました。
スレッド同士を待ち合わせるプログラムで、
3つのproducerと3つのconsumerが5つのキューで数字を入れ食いするプログラム(見ていただければわかると思います。)を作りたいのですが、どうすれば現在それぞれ2つずつのproducerとconsumerを3つずつランダムに動かせますか?
できれば具体的に教えていただけると助かります。
ご回答よろしくお願いいたします。

該当のソースコード

package thread;

public class ProducerConsumer {

    public static void main(String[] args) {
        MyQueue queue = new MyQueue(5);
        Producer producer = new Producer(queue);
        Consumer comsumer = new Consumer(queue);
        producer.start();
        comsumer.start();
    }
}

class MyQueue{
    int[] intbuf;
    int start;
    int count;
    public MyQueue(int size){
        intbuf = new int[size];
        start = 0;
        count = 0;
    }
    public synchronized void put(int n) throws InterruptedException{
        while(count >= intbuf.length){
            System.out.println(Thread.currentThread().getName() +"wait: バッファの空きを待つ");
            wait();
        }
    int end = (start + count) % intbuf.length;
    intbuf[end] = n;
    count++;
    notifyAll();
    }
    public synchronized int take() throws InterruptedException{
        while(count== 0){
            System.out.println(Thread.currentThread().getName() + "wait:データを待つ");
            wait();
        }
        int n = intbuf[start];
        start = (start+1) % intbuf.length;
        count--;
        notifyAll();
        return n;
    }
}    
class Producer extends Thread{
    static final int END = -1;
    MyQueue queue = null;
    Producer(MyQueue queue){
        this.queue = queue;
    }
    public void run(){
        try{
            for (int i = 1;i<100;i++){
                int n = produce(i);
                queue.put(n);
            }
            queue.put(Producer.END);
        }catch(InterruptedException e){
        }
    }
    int produce(int n){
        sleepRandomly();
        System.out.println("Producer:"+Thread.currentThread().getName() +"は"+"を生産完了");
        return n;
    }
    void sleepRandomly(){
        try{
            int n = (int)(Math.random()*1000);
            Thread.sleep(n);
        }catch (InterruptedException e){
        }
    }
}

class Consumer extends Thread{
    MyQueue queue = null;
    Consumer(MyQueue queue){
        this.queue = queue;
    }

    public void run(){
        try{
            while(true){
                int n = queue.take();
                if(n==Producer.END){
                    break;
                }
                consume(n);
            }
            }catch(InterruptedException e){
            }
        }
        void consume(int n){
            System.out.println("consumer:"+Thread.currentThread().getName()+"は"+n+"を消費中");
            sleepRandomly();
        }
        void sleepRandomly(){
            try{
                int n = (int)(Math.random()*1000);
                Thread.sleep(n);
            }catch(InterruptedException e){
            }
        }
}

実行結果

Thread-1wait:データを待つ
Producer:Thread-0はを生産完了
consumer:Thread-11を消費中
Producer:Thread-0はを生産完了
consumer:Thread-12を消費中
Thread-1wait:データを待つ
Producer:Thread-0はを生産完了
consumer:Thread-13を消費中
Producer:Thread-0はを生産完了
consumer:Thread-14を消費中
Thread-1wait:データを待つ
Producer:Thread-0はを生産完了
consumer:Thread-15を消費中
Thread-1wait:データを待つ
Producer:Thread-0はを生産完了
consumer:Thread-16を消費中
Thread-1wait:データを待つ
Producer:Thread-0はを生産完了
consumer:Thread-17を消費中
Producer:Thread-0はを生産完了
///

試したこと

課題に対してアプローチしたことを記載してください

補足情報(言語/FW/ツール等のバージョンなど)

より詳細な情報

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • M.M.O-05

    2016/12/16 17:12

    ありがとうございます。ProducerクラスとConsumerクラスは一つずつでお願いします。

    キャンセル

  • 退会済みユーザー

    2016/12/16 22:39

    こちらの質問が他のユーザから「問題・課題が含まれていない質問」という指摘を受けました
    teratailでは、漠然とした興味から票を募るような質問や、意見の主張をすることを目的とした投稿は推奨していません。
    「編集」ボタンから編集を行い、質問の意図や解決したい課題を明確に記述していただくと回答が得られやすくなります。

  • jimbe

    2019/01/23 11:36 編集

    Producer:Thread-0はを生産完了

    'は'と'を'の間にnが表示されていないようです.

    はともかく, yohhoyさんはクラスではなく「インスタンス」を必要なだけ作れば良いのではと言われています.
    参考にされた入門書にクラスとインスタンスの関係・違いについて書かれている箇所がありましたら, その辺りを見直されることをお勧めします.

    キャンセル

回答 1

0

ProducerとConsumerのインスタンスの合計数が奇数(3など)だったり両方の個数が不均衡な場合でも動くようにしたものが以下です

import java.util.concurrent.BlockingQueue; 
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
public class PRM{

    public static void main(String[] args) {
        BlockingQueue<Integer> queue = new LinkedBlockingQueue<>(5);
        Producer producer = new Producer(queue);

        Consumer comsumer = new Consumer(queue);
        Consumer comsumer2 = new Consumer(queue);

        producer.start();

        comsumer.start();
        comsumer2.start();

    }
}

class Producer extends Thread{
    static final int END = -1;
    BlockingQueue<Integer> queue = null;
    Producer(BlockingQueue<Integer> queue){
        this.queue = queue;
    }
    public void run(){
        try{
            for (int i = 1;i<10;i++){
                int n = produce(i);
                queue.put(n);
            }

        }catch(InterruptedException e){
        }
    }
    int produce(int n){
        sleepRandomly();
        System.out.println("Producer:"+Thread.currentThread().getName() +"は"+n+"を生産完了");
        return n;
    }
    void sleepRandomly(){
        try{
            int n = (int)(Math.random()*1000);
            Thread.sleep(n);
        }catch (InterruptedException e){
        }
    }
}

class Consumer extends Thread{
    BlockingQueue<Integer> queue = null;
    Consumer(BlockingQueue<Integer> queue){
        this.queue = queue;
    }

    public void run(){
        try{
            while(true){
        int n = queue.poll(4,TimeUnit.SECONDS);    
                consume(n);
        }
            }catch(NullPointerException e){

        }catch(InterruptedException e){
            }
        }
        void consume(int n){
            System.out.println("consumer:"+Thread.currentThread().getName()+"は"+n+"を消費中");
            sleepRandomly();
        }
        void sleepRandomly(){
            try{
                int n = (int)(Math.random()*1000);
                Thread.sleep(n);
            }catch(InterruptedException e){
            }
        }
}

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 87.80%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る