黑馬程式員————java線程之間的通訊

來源:互聯網
上載者:User

標籤:

------<a href="http://www.itheima.com" target="blank">Java培訓、Android培訓、iOS培訓、.Net培訓</a>、期待與您交流! -------

  多線程可以讓我們同時共用一個資源,但如果在共用這個資源時需要彼此之間的聯絡怎麼做呢?

經典執行個體:生產者與消費者。

問題描述,生產者每生產一個消費者就要取走一個,同時進行。

首先java為我們提供了一套等待喚醒機制,讓線程與線程之間產生了聯絡。線程是分五個狀態的:建立;運行;阻塞;凍結;消亡。java提供了幾個針對狀態的方法

wait()方法讓線程進入凍結狀態,讓出cpu,讓出鎖;

notify()方法喚醒進入凍結狀態的線程,notifyAll()是喚醒所有的線程。

針對問題,我們可以對生產者設定一個開關,如果資源為0就允許其生產並在生產完之後將開關關上,不會在有生產者生產並喚醒其他線程也就是消費者線程,當然在這之上同樣要用到同步,為了保證第一個生產者進去之時,其他生產者會被拒之門外,對於消費者同理。

public static void main(String[] args) {// tongbu i=new tongbu();//建立抽取出來的同步方法對象hjw j=new hjw(i);//建立實現Runnable介面的對象bb k=new bb(i);Thread xc1 =new Thread(j);//建立線程Thread xc2 =new Thread(k);xc1.setName("生產者");xc2.setName("消費者");xc1.start();xc2.start();}}class tongbu{//將兩個同步方法抽取出來private String name;private int count=1;boolean flag=false;//定義一個bool類型來作用等待喚醒機制public synchronized void set(String name){//生產者的同步函數if(flag){//已存在就睡眠try{wait();}catch(Exception e){}}//否則 運作代碼this.name=name+"---"+count++;System.out.println(Thread.currentThread().getName()+this.name);flag=true;//改變bool值this.notify();//喚醒線程}public synchronized void get(){if(!flag){//進入休眠try{wait();}catch(Exception e){}}//被生產者喚醒System.out.println(Thread.currentThread().getName()+"---"+this.name);flag=false;this.notify();//喚醒線程}}class hjw implements Runnable{private tongbu x ;hjw(tongbu x){//傳回tongbu對象this.x=x;}public void run(){//重寫run方法while(true){x.set("餅乾");}}}class bb implements Runnable{private tongbu x ;bb(tongbu x){//傳回tongbu對象this.x=x;}public void run(){//重寫run方法while(true){x.get();}}}

  這隻是對於生產者和消費者只有一個線程,如果這邊都有多個線程呢?絕不是多建立幾個線程那麼簡單,因為要notify方法是喚醒最先休眠的那個線程,也就是說轉到後面會出,生產一個,消費兩次,生產多個只消費其中一個。

那麼如何避免呢?採用while迴圈替代if迴圈,每當線程解凍之後,重新開始迴圈而非接著向下執行,這樣就避免了多次執行,但問題是依據notify()的特性還是會讓所有線程都陷入等待,我需要喚醒對方線程,所有這個時候就要用到notifyAll()了,喚醒所有線程。

public static void main(String[] args) {// tongbu i=new tongbu();//建立抽取出來的同步方法對象hjw j=new hjw(i);//建立實現Runnable介面的對象bb k=new bb(i);Thread xc1 =new Thread(j);//建立線程Thread xc2 =new Thread(k);xc1.setName("生產者");xc2.setName("消費者");xc1.start();xc2.start();}}class tongbu{//將兩個同步方法抽取出來private String name;private int count=1;boolean flag=false;//定義一個bool類型來作用等待喚醒機制public synchronized void set(String name){//生產者的同步函數while(flag){//已存在就睡眠try{wait();}catch(Exception e){}}//否則 運作代碼this.name=name+"---"+count++;System.out.println(Thread.currentThread().getName()+this.name);flag=true;//改變bool值this.notifyAll();//喚醒線程}public synchronized void get(){while(!flag){//進入休眠try{wait();}catch(Exception e){}}//被生產者喚醒System.out.println(Thread.currentThread().getName()+"---"+this.name);flag=false;this.notifyAll();//喚醒線程}}class hjw implements Runnable{private tongbu x ;hjw(tongbu x){//傳回tongbu對象this.x=x;}public void run(){//重寫run方法while(true){x.set("餅乾");}}}class bb implements Runnable{private tongbu x ;bb(tongbu x){//傳回tongbu對象this.x=x;}public void run(){//重寫run方法while(true){x.get();}}}

  事實上,java5.0版本提供更完善的解決方案,針對如何喚醒指定線程。在java.lang.util.concurrent.locks中,提供了方法將鎖顯示化用以取代同步synchronized,lock()開鎖,unlock()關鎖,關鎖這一特點猶如關閉資源就是無論怎樣都要執行,因為前面有異常需要處理,所以關鎖這一操作放在了finally{}中;而對於Object中wait()方法和notify(),notifyAll()方法分別用condition的await(),signal()和signalAll()取代,在lock中有一個new condition的方法,所以可以通過建立多個condition類,實現對指定線程的操作。

 

黑馬程式員————java線程之間的通訊

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.