手書き生産者--消費者モデルの例


同時プログラミングでは,比較的古典的なプログラミング例が生産者と消費者モデルである.次に、生産者と消費者とは何か、彼らの特徴と注意点を説明する例を示します.
1、まずデータオブジェクトを定義し、
public class Data {
    private String id;

    private String name;

    public Data(String id,String name){
        this.id = id;
        this.name = name;
    }
    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Data [id=" + id + ", name=" + name + "]";
    }
}

2.Runnableインタフェースを実装する生産者を定義します.
public class Provider implements Runnable{
    //     
    private BlockingQueue queue;

    //          ,             ,        
    private volatile boolean isRunning = true;
    //id   
    private static AtomicInteger count = new AtomicInteger();

    //    
    private static Random r = new Random();

    public Provider(BlockingQueue queue){
        this.queue = queue;
    }

    @Override
    public void run() {
        while(isRunning){
            //    0-1000         
            try {
                Thread.sleep(r.nextInt(1000));
                //         
                int id  = count.incrementAndGet();
                //      getData()     
                Data data = new Data(Integer.toString(id),"  "+id);
                System.out.println("    :"+ Thread.currentThread().getName() + ",     ,id :"+ id+ ",           。。。");
                if(!this.queue.offer(data,2,TimeUnit.SECONDS)){
                    System.out.print("         ");
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.print("aaa");
        }
    }

    public void  stop(){
        this.isRunning = false;
    }
}

ここでいくつかの注意点があります.1つは、共有バッファの選択であり、生産者-消費者モデルとして、共有バッファは必ずブロックする能力を備えなければなりません.だからここで選んだのはブロックキューです.もう1つは,同時プログラミングの場合,i++のようなid自己成長機能を使用する必要がある場合,Atomicパッケージの下の同時クラスを使用する必要がある.これらのクラスはCAS設計を採用しているため、同時問題は発生しません.
3.消費者
public class Consumer implements Runnable {

    private BlockingQueue queue;

    public Consumer(BlockingQueue queu){
        this.queue = queu;
    }

    //    
    private static Random r = new Random();

    @Override
    public void run() {
        while(true){
            try{
                //    
                Data data = this.queue.take();
                //      ,   0-1000      
                Thread.sleep(r.nextInt(1000));
                System.out.print("      "+Thread.currentThread().getName() +",    ,  id "+data.getId());
            }catch(InterruptedException e){
                e.printStackTrace();
            }
        }
    }
}

消費者は主にブロックキューからデータを取得し、キューに要素がない場合はCPUを解放し、待機します.(注意ここではpollではなくtakeを使用していますが、takeは要素がないときにCPUを解放し、pollはnullに直接戻る点が違います).
main関数:
public class Main {
    public static void main(String[] args){
        //     
        BlockingQueue queue = new LinkedBlockingQueue(10);
        //   
        Provider p1 = new Provider(queue);
        Provider p2 = new Provider(queue);
        Provider p3 = new Provider(queue);

        Consumer c1 = new Consumer(queue);
        Consumer c2 = new Consumer(queue);
        Consumer c3 = new Consumer(queue);

        //     ,          ,          ,            ,          60s。
        ExecutorService cachepool = Executors.newCachedThreadPool();
        cachepool.execute(p1);
        cachepool.execute(p2);
        cachepool.execute(p3);
        cachepool.execute(c1);
        cachepool.execute(c2);
        cachepool.execute(c3);
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        p1.stop();
        p2.stop();
        p3.stop();
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}