マルチスレッドの消費者生産者問題


消費者生産者の問題:
この問題はマルチスレッド同期問題の古典的な例であり,生産者が生産対象を担当し,消費者が生成者が生成した対象を取り出すことを担当し,両者はこの過程を繰り返している.このプロセスでは、いくつかの問題に注意する必要があります.
生産者と消費者の数にかかわらず、保証しなければならない.
1.生産者が毎回産出する対象は異なっていなければならず、発生した対象は一度しか現れない.
2.消費者は毎回取り出す対象が異なっていなければならない.取り出す対象は一度しか現れない.
3.必ず先にそのオブジェクトを生成してから、オブジェクトが取り出され、順序が乱れてはいけない.
1つ目のケース:
複数の生産者が交代で生産を担当し、複数の消費者が取り出す.生産者が1つの対象を生成すると、他の生産者は生産できず、消費者が取り出し操作を実行するしかない.
必要な対象は商品類、消費者、生産者である.
//   
public class ProducerConsumer {

    public static void main(String[] args) {
        //       
        Resource r = new Resource();

        //             
        Producer p = new Producer(r);
        Consumer c = new Consumer(r);

        //      ,2      ,     
        Thread t1 = new Thread(p);
        Thread t2 = new Thread(p);
        Thread t3 = new Thread(c);
        Thread t4 = new Thread(c);

        t1.start();
        t2.start();
        t3.start();
        t4.start();
    }

}

//   
class Resource{
    private String name;
    private int count = 1;
    private  boolean flag = false;

    //    
    public synchronized void set(String name) {
        while (flag) {
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        this.name = name + "---" + count++;
        System.out.println(Thread.currentThread().getName() + "    " + this.name);
        flag = true;
        //      
        this.notifyAll();

    }
    //    
    public synchronized void out() {
            while (!flag) {
                try {
                    wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println(Thread.currentThread().getName() + "    ________" + this.name);
            flag = false;
            this.notifyAll();
    }
}

//     
class Producer implements Runnable{

    private Resource res;

    public Producer(Resource res) {
        this.res = res;
    }

    @Override
    public void run() {
        while (true) {
            res.set("+  +");
        }
    }
}

//     
class Consumer implements Runnable{

    private Resource res;

    Consumer(Resource res) {
        this.res = res;
    }

    @Override
    public void run() {
        while (true) {
            res.out();
        }
    }
}

実行結果は1つ生成され、すぐに1つ取り出し、ループを繰り返し、その実行結果の部分は以下の通りです.
Thread-2    ________+  +---67821
Thread-1    +  +---67822
Thread-3    ________+  +---67822
Thread-0    +  +---67823
Thread-2    ________+  +---67823
Thread-1    +  +---67824
Thread-3    ________+  +---67824
Thread-0    +  +---67825
Thread-2    ________+  +---67825
Thread-1    +  +---67826
Thread-3    ________+  +---67826
Thread-0    +  +---67827
Thread-2    ________+  +---67827
Thread-1    +  +---67828
Thread-3    ________+  +---67828
Thread-0    +  +---67829
Thread-2    ________+  +---67829
Thread-1    +  +---67830
Thread-3    ________+  +---67830
Thread-0    +  +---67831
Thread-2    ________+  +---67831
Thread-1    +  +---67832

2つ目のケース:
目標:生産者と消費者が交代して実行権を奪うが、生産者は最大5個の在庫を持つことができ、消費者は最大5個を連続的に取り出すことができる
中間オブジェクト:倉庫クラスを定義する必要があります.このクラスは、生産者と消費者が共有する領域であり、データ型がチェーンテーブルの結果を選択して生成されたオブジェクトを格納します.倉庫は容量の上限があり、数量が上限に達した後、生産者は製品の生産を継続することを許さない.現在のスレッドは待機状態に入り、他のスレッドの起動を待つ.倉庫に製品がない場合、消費者は消費を継続することを許さず、現在のスレッドは待機状態に入り、他のスレッドの起動を待つ.
1つ目の解決策は、wait()とnotifyAll()を組み合わせた同期コードブロック(synchronized)を採用することである. の方法で、具体的なコードは以下の通りです.
package Thread;
/**
 * 2    ,3    
 */

import java.util.LinkedList;

public class ProConThreadDemo {
    public static void main(String[] args) {
        Respository res = new Respository();

        //  2    ,3    
        Worker p1 = new Worker(res,"  ");
        Worker p2 = new Worker(res,"  ");
        Worker p3 = new Worker(res,"  ");
        Constomer c1 = new Constomer(res);
        Constomer c2 = new Constomer(res);

        Thread t1 = new Thread(p1," ");
        Thread t2 = new Thread(p2," ");
        Thread t3 = new Thread(p3," ");
        Thread t4 = new Thread(c1,"aaa");
        Thread t5 = new Thread(c2,"bbb");

        t1.start();
        t2.start();
        t3.start();
        t4.start();
        t5.start();

    }



}
//   
class Respository{

    private LinkedList store = new LinkedList();

    //      ,       
    //                .
    public synchronized void push(Product p,String ThreadName){
        //          5   
        /*         5,     5         .        
         *        ,         5 ,                .
         */
        while (store.size()==5){
            try {
                System.out.println(ThreadName+"   :    ,      ");
                //        ,      ,      ,        .
                this.wait();
            }catch (InterruptedException e){
                e.printStackTrace();
            }
        }
        this.notifyAll();
        store.addLast(p);
        System.out.println(ThreadName+"       "+p.Name+p.Id+"     "+"       :"+store.size());
        //          ,        0.1 
        try {
            Thread.sleep(100);
        }catch (InterruptedException e){
            e.printStackTrace();
        }

    }


    //      ,      
    //                .
    public synchronized void pop(String ThreadName){
        /*         ,         .         
         *        ,         0 ,                .
         */
        while (store.size()==0){
            try {
                System.out.println(ThreadName+"   :    ,      ");
                //        ,      ,      ,        .
                this.wait();
            }catch (InterruptedException e){
                e.printStackTrace();
            }
        }
        this.notifyAll();
        //    。  pollFirst()       ,
        Product p = store.pollFirst();
        System.out.println(ThreadName+"   "+p.Name+p.Id+"       :"+store.size());
        //          ,       0.1 
        try {
            Thread.sleep(100);
        }catch (InterruptedException e){
            e.printStackTrace();
        }

    }


}


//   
class Product{
    //       Id
    public int Id;
    //     
    public String Name;

    public Product(String name, int id) {
        Name = name;
        Id = id;
    }

}

//   
class Worker implements Runnable{
    //   volatile       Id     ,  Id   ,        Id   ,      
    //    run       ,     Id                Id      
    public volatile Integer Id = 0;

    public volatile String name;

    //      
    private Product p;
    //      
    Respository res;

    boolean flag = true;

    public Worker(Respository res,String name) {
        this.res = res;
        this.name = name;
    }

    @Override
    public void run() {
        while (flag){
            p  = new Product(name,Id);
            res.push(new Product(this.p.Name,Id++),Thread.currentThread().getName());
        }
    }
}

class Constomer implements Runnable{
    boolean flag = true;

    //      
    Respository res;

    public Constomer(Respository res) {
        this.res = res;
    }

    @Override
    public void run() {
        while (flag) {

            res.pop(Thread.currentThread().getName());


        }

    }
}

運転結果は以下の通りで、倉庫の最大在庫は5個で、実際の生産に近い.
aaa   :    ,      
          0            :1
          0            :2
          0            :3
bbb     0       :2
bbb     0       :1
          1            :2
          1            :3
          1            :4
aaa     0       :3
aaa     1       :2
aaa     1       :1
aaa     1       :0
aaa   :    ,      
          2            :1
          2            :2
          2            :3
bbb     2       :2
bbb     2       :1
          3            :2
          3            :3
          3            :4
aaa     2       :3
          4            :4
          5            :5

第2の方法、利用 lockクラス置換 synchronizedの使用により、コードを最適化することができ、主に起動時に条件に基づいて指定されたスレッドを起動することができます.たとえば、在庫が空の場合、最初の方法は、待機しているすべてのスレッドを呼び出し、取り出したスレッドも含む.このときlockクラスは在庫が空の場合に設定でき、生産スレッドのみを起動し、取り出したスレッドは依然として待機状態にあり、具体的なコードは以下の通りである.
package Thread;

import java.util.LinkedList;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class ProConThreadPool {

    public static void main(String[] args) {

       Respository res = new Respository();

       Worker p1 = new Worker(res,"  ");
       Worker p2 = new Worker(res,"  ");
       Worker p3 = new Worker(res,"  ");

       Constomer c1 = new Constomer(res);
       Constomer c2 = new Constomer(res);

       Thread t1 = new Thread(p1," ");
       Thread t2 = new Thread(p2," ");
       Thread t3 = new Thread(p3," ");
       Thread t4 = new Thread(c1,"aaa");
       Thread t5 = new Thread(c2,"bbb");

       t1.start();
       t2.start();
       t3.start();
       t4.start();
       t5.start();

    }



}
//   
class Respository{

    private Lock lock = new ReentrantLock();

    private LinkedList store = new LinkedList();

    private Condition condition_pro = lock.newCondition();
    private Condition condition_con = lock.newCondition();

    public LinkedList getStore() {
        return store;
    }

    public void setStore(LinkedList store) {
        this.store = store;
    }
    //     
    public  void push(Product p,String ThreadName) throws InterruptedException{
        lock.lock();
        try {
            //          5   
            while (store.size()==5){
                    System.out.println(ThreadName+"   :    ,      ");
                    condition_pro.await();
            }
            condition_con.signalAll();
            store.addLast(p);
            System.out.println(ThreadName+"       "+p.Name+p.Id+"     "+"       :"+store.size());

        }finally {
            lock.unlock();
        }
        try {
            Thread.sleep(100);
        }catch (InterruptedException e){
            e.printStackTrace();
        }

    }


    //    
    public void pop(String ThreadName) throws InterruptedException
    {
        lock.lock();
        try{
            while (store.size()==0){

                    System.out.println(ThreadName+"   :    ,      ");
                    condition_con.await();
            }
            condition_pro.signalAll();
            Product p = store.pollFirst();
            System.out.println(ThreadName+"   "+p.Name+p.Id+"       :"+store.size());

        }
        finally {
            lock.unlock();
        }
        try {
            Thread.sleep(100);
        }catch (InterruptedException e){
            e.printStackTrace();
        }

    }


}



class Product{
    public int Id;

    public String Name;

    public Product(String name, int id) {
        Name = name;
        Id = id;
    }

}

class Worker implements Runnable{

    public volatile Integer Id = 0;

    public volatile String name;

    //      
    private Product p;
    //      
    Respository res;

    boolean flag = true;

    public Worker(Respository res,String name) {
        this.res = res;
        this.name = name;
    }

    @Override
    public void run(){
        while (flag){
                p  = new Product(name,Id);
                try {
                    res.push(new Product(this.p.Name,Id++),Thread.currentThread().getName());
                }catch (InterruptedException e){
                    e.printStackTrace();
                }

            }
    }
}

class Constomer implements Runnable{
    boolean flag = true;

    //      
    Respository res;

    public Constomer(Respository res) {
        this.res = res;
    }

    @Override
    public void run() {
        while (flag) {
            try {
                res.pop(Thread.currentThread().getName());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

    }
}

実行結果は、次のようになります.
aaa   :    ,      
bbb   :    ,      
          0            :1
          0            :2
          0            :3
aaa     0       :2
bbb     0       :1
bbb     0       :0
          1            :1
          1            :2
aaa     1       :1
          1            :2
aaa     1       :1
          2            :2
          2            :3
bbb     1       :2
          2            :3
aaa     2       :2
          3            :3
bbb     2       :2
          3            :3
          3            :4