Java基礎教程:多線程基礎(3)——阻塞隊列

來源:互聯網
上載者:User

標籤:zed   資訊   基礎教程   for   nbsp   功能   解決   取數   生產者   

Java基礎教程:多線程基礎(3)——阻塞隊列快速開始引入問題

  生產者消費者問題是執行緒模式中的經典問題:生產者和消費者在同一時間段內共用同一儲存空間,生產者向空間裡生產資料,而消費者取走資料

類比情景

  這裡我們實現如下的情況的生產-消費模型:

生產者不斷交替地生產兩組資料“姓名--1-->內容--1”,“姓名--2-->內容--2”,這裡的“姓名--1”和“姓名--2”類比為資料的名稱,“內容--1 ”和“內容--2 ”類比為資料的內容

由於本程式中牽扯到線程啟動並執行不確定性,因此可能會出現以下問題:

  1.假設生產者線程剛向資料存放區空間添加了資料的名稱,還沒有加入該資訊的內容,程式就切換到了消費者線程,消費者線程把資訊的名稱和上一個資訊的內容聯絡到了一起;

  2.生產者生產了若干條資料,消費者才可以取資料,或者是,消費者取完一次資料後,還沒等生產者放入新的資料,又重複取出了已取過的資料。

通過分析我們可知:

  第一個問題可以通過同步來解決,第二個問題就需要用到線程通訊。生產者線程放入資料後,通知消費者線程取出資料,消費者線程取出資料後,通知生產者線程生產資料,這裡用wait\notigy機制來實現。

Java代碼定義資訊類
package thread;public class Info {    private String name = "name";    private String content = "content";    //設定標誌位,用來進行線程通訊    private boolean flag =true;    /**     * 設定訊息,此處用到線程同步     * @param name     * @param content     */    public synchronized void set(String name,String content)    {        while (!flag)        {            try {                super.wait();            } catch (InterruptedException e) {                e.printStackTrace();            }        }        this.name=name; //設定名稱        try {            Thread.sleep(1000);        } catch (InterruptedException e) {            e.printStackTrace();        }        this.content=content; //設定內容        flag =false; //設定標誌位,表示現在生產停止,可以取走!    }    public synchronized void get()    {        while (flag)        {            try {                super.wait();            } catch (InterruptedException e) {                e.printStackTrace();            }        }        try {            Thread.sleep(300);        } catch (InterruptedException e) {            e.printStackTrace();        }        System.out.println(name +                " --> " + content) ;        flag  = true ;  // 改變標誌位,表示可以生產        super.notify();    }}  
定義生產者
public class Producer implements Runnable {    private Info info=null;    public Producer(Info info)    {        this.info=info;    }    @Override    public void run() {        boolean flag = true ;   // 定義標記位        for(int i=0;i<10;i++){            if(flag){                this.info.set("姓名--1","內容--1") ;    // 設定名稱                flag = false ;            }else{                this.info.set("姓名--2","內容--2") ;    // 設定名稱                flag = true ;            }        }    }}
定義消費者
public class Consumer implements Runnable {    private Info info = null ;    public Consumer(Info info){        this.info = info ;    }    public void run(){        for(int i=0;i<10;i++){            this.info.get() ;        }    }    public static void main(String[] args) {        Info info = new Info(); // 執行個體化Info對象        Producer pro = new Producer(info) ; // 生產者        Consumer con = new Consumer(info) ; // 消費者        new Thread(pro).start() ;        //啟動了生產者線程後,再啟動消費者線程        try{            Thread.sleep(500) ;        }catch(InterruptedException e){            e.printStackTrace() ;        }        new Thread(con).start() ;    }}
 使用阻塞隊列來實現相同功能引入 BlockingQueue

  任何有效生產者-消費者問題解決方案都是通過控制生產者put()方法(生產資源)和消費者take()方法(消費資源)的調用來實現的,一旦你實現了對方法的阻塞控制,那麼你將解決該問題。Java通過BlockingQueue提供了開箱即用的支援來控制這些方法的調用(一個線程建立資源,另一個消費資源)。java.util.concurrent包下的BlockingQueue介面是一個安全執行緒的可用於存取對象的隊列

  

  BlockingQueue是一種資料結構支援一個線程往裡存資源,另一個線程從裡取資源。這正是解決生產者消費者問題所需要的,那麼讓我們開始解決該問題吧。

Java代碼訊息類
public class InfoPlus {    private String name = "name";    private String content = "content";    public InfoPlus(String name, String content) {        this.name = name;        this.content = content;    }    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    public String getContent() {        return content;    }    public void setContent(String content) {        this.content = content;    }    @Override    public String toString() {        return "InfoPlus{" +                "name=‘" + name + ‘\‘‘ +                ", content=‘" + content + ‘\‘‘ +                ‘}‘;    }}
生產者
import java.util.concurrent.BlockingQueue;public class ProducerPlus implements Runnable {    private BlockingQueue<InfoPlus> queue;    public ProducerPlus(BlockingQueue<InfoPlus> queue) {        this.queue = queue;    }    @Override    public void run() {        for (int i=0;i<10;i++)        {            try {                Thread.sleep(1000);                queue.put(new InfoPlus("name"+i,"content"+i));            } catch (InterruptedException e) {                e.printStackTrace();            }        }    }}
消費者
import java.util.concurrent.BlockingQueue;import java.util.concurrent.LinkedBlockingDeque;public class ConsumerPlus implements Runnable{    private BlockingQueue<InfoPlus> queue;    public ConsumerPlus(BlockingQueue<InfoPlus> queue) {        this.queue = queue;    }    public void run() {        while (true) {            try {                System.out.println(this.queue.take());            } catch (InterruptedException e) {                e.printStackTrace();            }        }    }    public static void main(String[] args) {        BlockingQueue<InfoPlus> blockingQueue = new LinkedBlockingDeque<>();        ProducerPlus producerPlus = new ProducerPlus(blockingQueue);        ConsumerPlus consumerPlus = new ConsumerPlus(blockingQueue);        ConsumerPlus consumerPlus1 = new ConsumerPlus(blockingQueue);        new Thread(producerPlus).start();        new Thread(consumerPlus).start();        new Thread(consumerPlus1).start();    }}

 

Java基礎教程:多線程基礎(3)——阻塞隊列

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.