歡迎您光臨本站 註冊首頁

JAVA 線程通信相關知識彙總

←手機掃碼閱讀     e36605 @ 2020-06-17 , reply:0

兩個線程之間的通信

多線程環境下CPU會隨機的在線程之間進行切換,如果想讓兩個線程有規律的去執行,那就需要兩個線程之間進行通信,在Object類中的兩個方法wait和notify可以實現通信。

wait方法可以使當前線程進入到等待狀態,在沒有被喚醒的情況下,線程會一直保持等待狀態。
 notify方法可以隨機喚醒單個在等待狀態下的線程。

來實現這樣的一個功能:
 讓兩個線程交替在控制檯輸出一行文字

定義一個Print類,有兩個方法print1和print2,分別打印一行不同的內容

  package com.sutaoyu.volatlt;    public class Print {   private int flag = 1;      public void print1() {    synchronized(this) {     if(flag != 1) {      try {       //讓當前線程進入等入狀態       this.wait();      }catch(InterruptedException e) {       e.printStackTrace();      }     }          System.out.println("monkey");     flag = 2;     //隨機的喚醒單個等待的線程     this.notify();    }   }         public void print2() {    synchronized(this) {     if(flag != 2) {     try {      this.wait();     }catch (InterruptedException e){      e.printStackTrace();     }    }    System.out.println("1024");    flag = 1;    this.notify();    }   }  }

 

定義線程測試類,開啟兩個線程,分別運行Print類中print1和print2方法

  package com.sutaoyu.volatlt;    public class NotifyTest01 {   public static void main(String[] args) {    Print p = new Print();    Thread t1 = new Thread() {     public void run() {      while(true) {       p.print1();      }     }    };        Thread t2 = new Thread() {     public void run() {      while(true) {       p.print2();      }     }    };    t1.start();    t2.start();   }  }

 

三個及三個以上的線程之間的通信

改造上面代碼在Print類中添加一個print3方法,再開啟第三個線程來執行這個方法。

另外需要修改的地方是:

1.因為notifyAll方法可以喚醒所有等待狀態的線程,所有用notifyAll方法來替代notify方法

2.當線程被喚醒後,需要先判斷一下flag的值,if不會重新判斷flag值,而while會重新判斷flag的值,所以將Print中的if判斷修改為while判斷。

  package com.sutaoyu.volatlt;    public class Print {   private int flag = 1;      public void print1() {    synchronized(this) {     while(flag != 1) {      try {       //讓當前線程進入等入狀態       this.wait();      }catch(InterruptedException e) {       e.printStackTrace();      }     }          System.out.println("monkey");     flag = 2;     //隨機的喚醒單個等待的線程     this.notifyAll();    }   }         public void print2() {    synchronized(this) {     while(flag != 2) {     try {      this.wait();     }catch (InterruptedException e){      e.printStackTrace();     }    }    System.out.println("1024");    flag = 3;    this.notifyAll();    }   }      public void print3() {    synchronized(this) {     while(flag != 3) {      try {       this.wait();      }catch(InterruptedException e) {       e.printStackTrace();      }     }          System.out.println("888");     flag = 1;     this.notifyAll();    }   }  }

 

  package com.sutaoyu.volatlt;    public class NotifyTest01 {   public static void main(String[] args) {    Print p = new Print();    Thread t1 = new Thread() {     public void run() {      while(true) {       p.print1();      }     }    };        Thread t2 = new Thread() {     public void run() {      while(true) {       p.print2();      }     }    };        Thread t3 = new Thread() {     public void run() {      while(true) {       p.print3();      }     }    };        t1.start();    t2.start();    t3.start();   }  }

 

線程通信注意事項
 

在print1,2,3方法中同步代碼塊中使用哪個對象作為鎖,那在調用wait和notify方法時一定要調用這個對象上的wait和notify方法。
 上面程序使用this作為對象鎖,在下面調用的都是this.wait()和this.notify()方法。

在多線程執行當中
 wait方法釋放對象鎖,根據上面的代碼示例,t1,t2,t3三個線程使用的是同一個對象鎖,如果wait方法不釋放鎖的話,別的線程就不能獲取到該鎖,也就不能獲取cpu的執行權了。
 

sleep和notify方法不釋放對象鎖,上面代碼示例中,如果notify方法釋放鎖的話,別的線程就有可能獲取到cpu的執行權,這樣子就會導致當前notify方法後面的代碼還未執行完畢就失去了cpu的執行權,從而導致一些問題,只有當線程執行完synchronized代碼塊後才會釋放鎖。



[e36605 ] JAVA 線程通信相關知識彙總已經有229次圍觀

http://coctec.com/docs/java/show-post-238872.html