1. 程式人生 > 程式設計 >JAVA 執行緒通訊相關知識彙總

JAVA 執行緒通訊相關知識彙總

兩個執行緒之間的通訊

多執行緒環境下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程式碼塊後才會釋放鎖。

以上就是JAVA 執行緒通訊相關知識彙總的詳細內容,更多關於JAVA 執行緒通訊的資料請關注我們其它相關文章!