生產者消費者阻塞隊列版(筆記)

 首先我們瞭解BlockingQueue的核心方法:

方法類型 拋出異常 特殊值 阻塞 超時
插入 add(e) offer(e) put(e) offer(e,time,unit)
移除 remove() poll() take() poll(time,unit)
檢查 element() peek() 不可用 不可用
拋出異常

當阻塞隊列滿時,再往隊列裏add插入元素會拋出llegalStateException;Queue full

當阻塞隊列空時,再往隊列裏remove移除元素會拋出NoSuchElementException

特殊值

插入方法:成功true 失敗false

移除方法:成功返回隊列的元素,隊列中沒有則返回null

一直阻塞

當阻塞隊列滿時,生產者線程繼續往隊列裏put元素,隊列會一直阻塞生產線程直到put數據或響應中斷退出。

當阻塞隊列空時,消費者線程試圖從隊列裏take元素,隊列會一直阻塞消費者線程直到隊列可用

超時退出 當阻塞隊列滿時,隊列會阻塞生產者線程一定時間,超過時間後生產者線程會退出。
package com.java.thread.blockingQueue;



import org.omg.PortableServer.THREAD_POLICY_ID;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

class MyResource{
    public volatile boolean FLAG=true;//默認開啓,進行生產+消費
    private AtomicInteger atomicInteger=new AtomicInteger();

    BlockingQueue<String> blockingQueue=null;

    public MyResource(BlockingQueue<String> blockingQueue){
        this.blockingQueue=blockingQueue;
        System.out.println(blockingQueue.getClass().getName());
    }

    //生產
    public void myProd() throws Exception{
        String data=null;
        boolean retValue;

        while(FLAG){
            data=atomicInteger.incrementAndGet()+"";
            retValue=blockingQueue.offer(data,2L, TimeUnit.SECONDS);
            if(retValue){
                System.out.println(Thread.currentThread().getName()+"\t"+"插入隊列"+data+"成功");
            }else{
                System.out.println(Thread.currentThread().getName()+"\t"+"插入隊列"+data+"失敗");
            }
            TimeUnit.SECONDS.sleep(1);
        }
        System.out.println(Thread.currentThread().getName()+"\t"+"大老闆叫停了,表示FLAG=false,生產動作結束");
    }

    //消費
    public void myConsumer() throws Exception{
        String result=null;

        while(FLAG){
            result=blockingQueue.poll(2L,TimeUnit.SECONDS);
            if(null==result||result.equals("")){
                FLAG=false;
                System.out.println(Thread.currentThread().getName()+"\t"+"超過2秒鐘沒有取到蛋糕,消費退出");
                System.out.println();
                System.out.println();
                return;
            }
            System.out.println(Thread.currentThread().getName()+"\t"+"消費者隊列"+result+"成功");
        }
    }

}

/**
 * 這個是有問題的吧,假如有多個消費者,那不是有的消費者會導致沒有消息消費,導致FLAG爲false,生產者也會因此退出。
 * 還有就是,萬一生產者生產的時間大於2秒呢?也會導致消費者超時。
 *
 * 而且有條數據會先消費後生產?---這個應該是壓入數據的時候(retValue=blockingQueue.offer(data,2L, TimeUnit.SECONDS);)和
 * 輸出結果的時候有延時 (System.out.println(Thread.currentThread().getName()+"\t"+"插入隊列"+data+"成功");)
 */
public class ProdConsumer_BlockQueueDemo {


    public static void main(String[] args) {
        MyResource myResource=new MyResource(new ArrayBlockingQueue<String>(10));

        new Thread(()->{
            System.out.println(Thread.currentThread().getName()+"\t 生產線程啓動");
            try {
                myResource.myProd();
                System.out.println();
                System.out.println();
            } catch (Exception e) {
                e.printStackTrace();
            }
        },"Prod").start();

        new Thread(()->{
            System.out.println(Thread.currentThread().getName()+"\t 消費線程啓動");
            try {
                myResource.myConsumer();
            } catch (Exception e) {
                e.printStackTrace();
            }
        },"Consm").start();


        //暫停一會兒線程
        try{TimeUnit.SECONDS.sleep(5);}catch (InterruptedException e){e.printStackTrace();}

        System.out.println();
        System.out.println();
        System.out.println();
        System.out.println("5秒時間到,大老闆叫停");
        myResource.FLAG=false;
    }

}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章