黑馬程序員_

--------------------ASP.Net+Android+IOS開發.Net培訓、期待與您交流! --------------------


1.  線程間通信

       1. 概述

    線程間通信:就是不同的線程共享同一資源,然後對資源進行不同的操作行爲,說白了,在執行的線程運行代碼是不一樣的,但是代碼中還含有共享資源。

      2. 舉例說明

  例如:例如就是有一資源(Res  煤),有兩個線程分別執行的是賦值和取出(兩輛卡車,一個是運來,一個是運走)

 

                   

/*共享的資源*/
public class Res {
  private String name;
  private String sex;
 
  public String getName() {
    return name;
  }
 
  public void setName(String name) {
    this.name = name;
  }
 
  public StringgetSex() {
    return sex;
  }
 
  public void setSex(String sex) {
    this.sex = sex;
  }
 
}
/*輸入類*/
public class Input implements Runnable {
  private Res r = null;// 定義了一個資源
 
  public Input(Res r) {// 通過構造方法初始化
    this.r = r;
  }
 
  public void run() {
    int x = 0;
    while (true) {
      if (x == 0) {
         this.r.setName("張三");
         this.r.setSex("男");
      } else {
         this.r.setName("Joney");
         this.r.setSex("female");
      }
 
      x = (x + 1) % 2;
    }
 
  }
}
/*輸出類*/
public class Output implements Runnable {
  private Res re = null;
 
  public Output(Res r) {//初始化資源
    this.re = r;
  }
 
  public void run() {
    while (true) {  
         System.out.println(this.re.getName() + ":" + this.re.getSex());
     
    }
  }
 
}
 
/*測試類*/
public class Text {
  public static void main(String[] agrs) {
    Res r = new Res();
    Input in = new Input(r);
    Output out = new Output(r);
    new Thread(in).start();
    new Thread(out).start();
 
  }
}
從結果中可以看出,結果和我們預測的結果不一樣,會出現這樣的結果:
Joney:男
張三:female
Joney:female
張三:男
張三:female


      3. 優化通信

           優化,剛纔的通信,就是加上同步鎖,在加鎖之前,一定要明確,必須是兩個或者是多個線程,鎖的對象必須是同一個鎖

   

                  

 /*輸入類*/
public class Input implements Runnable {
  private Res r = null;// 定義了一個資源
 
  public Input(Res r) {// 通過構造方法初始化
    this.r = r;
  }
 
  public void run() {
    int x = 0;
    while (true) {
      synchronized (r) {//加鎖,對象指定的是共享資源
         if (x == 0) {
           this.r.setName("張三");
           this.r.setSex("男");
         } else {
           this.r.setName("Joney");
           this.r.setSex("female");
         }
      }
      x = (x + 1) % 2;
    }
 
  }
}
/*輸出類*/
public class Output implements Runnable {
  private Res re = null;
 
  public Output(Res r) {//初始化資源
    this.re = r;
  }
 
  public void run() {
    while (true) {
      synchronized (re) {//加鎖,對象指定的是共享資源
         System.out.println(this.re.getName() + ":" + this.re.getSex());
      }
    }
  }
 
}



     這樣結果就是相匹配了,這樣我們一定要靈活運用同步,並且記住同步需要的條件。

2. 等待喚醒機制

     1. 概述和機制

                利用wait(),notify()和notifyAll()三個方法。

     wait()方法是線程放棄的執行資格,notify()喚醒監視器上等待的線程,默認的是從第一個開始。notifyAll()喚醒的是監視器(鎖)上所有等待的線程。爲什麼這三個函數都是在Object類中,因爲監視器(鎖)對象是任何對象,要用對象來是線程等待和喚醒,那麼就得放在Object類中,才能調用任何對象的方法。

     在共享資源資源上,定義了一個可以標識資源狀態 的標識位,在監視器判斷標誌位,若不符合執行條件則是線程等待,用此時監視器對象來使線程等待,否則繼續執行,到最後改變標誌位,然後喚醒的等待的線程(是另外一個共享資源的線程),同樣另外一個線程(或者是多個)會執行同樣的操作。

 

    只有同一個鎖上的被等待的線程,可以被同一個鎖上的notify()喚醒,不能對不同鎖上的線程進行喚醒,就是等待和喚醒必須是同一個鎖。


  

      2. 舉例

    

                 

/*共享的資源*/
public class Res {
  private String name;
  private String sex;
  private boolean flag = false;//標誌位,用來表示資源的狀態
 
  public boolean isFlag() {
    return flag;
  }
 
  public void setFlag(boolean flag) {
    this.flag = flag;
  }
 
  public String getName() {
    return name;
  }
 
  public void setName(String name) {
    this.name = name;
  }
 
  public String getSex() {
    return sex;
  }
 
  public void setSex(String sex) {
    this.sex = sex;
  }
 
}
/*輸入類*/
public class Input implements Runnable {
  private Res r = null;// 定義了一個資源
 
  public Input(Res r) {// 通過構造方法初始化
    this.r = r;
  }
 
  public void run() {
    int x = 0;
    while (true) {
      synchronized (r) {// 加鎖,對象指定的是共享資源
         if (r.isFlag())// flag=true表示此時裏面有資源,或者是資源沒有被讀取呢,不能繼續添加
           try {
             r.wait();
           } catch (InterruptedException e) {
             e.printStackTrace();
           }
         if (x == 0) {
           this.r.setName("張三");
           this.r.setSex("男");
         } else {
           this.r.setName("Joney");
           this.r.setSex("female");
         }
         x = (x + 1) % 2;
         r.setFlag(true);// 標識此時已經賦值了,不能在連續賦值了
         r.notify();
      }
 
    }
 
  }
}
/*輸出類*/
public class Output implements Runnable {
  private Res r = null;
 
  public Output(Res r) {// 初始化資源
    this.r = r;
  }
 
  public void run() {
    while (true) {
      synchronized (r) {
         if (!r.isFlag())// flag=false,標識此時沒有資源,或者資源已經被讀取了
           try {
             r.wait();
           } catch (InterruptedException e) {
             e.printStackTrace();
           }
         System.out.println(this.r.getName() + ":" + this.r.getSex());
         r.setFlag(false);// 讀取資源後,然後把標誌爲false,標識此時已經被讀取出來了,不能在讀取了
         r.notify();
      }
    }
  }
 
}
/*測試類*/
public class Text {
  public static void main(String[] agrs) {
    Res r = new Res();
    Input in = new Input(r);
    Output out = new Output(r);
    new Thread(in).start();
    new Thread(out).start();
 
  }
}
 
結果:
張三:男
Joney:female
張三:男
Joney:female
張三:男
Joney:female
張三:男
Joney:female
張三:男


3.優化例子

   在共享資源中使用同步方法老設置名稱和取值


/*共享的資源*/
public class Res {
  private String name;
  private String sex;
  private boolean flag = false;// 標誌位,用來表示資源的狀態
/*同步函數賦值對象是 this*/
  public synchronized void set(String name, String sex) {// 使用同步函數
    if (flag)
      try {
         this.wait();
      } catch (InterruptedException e) {
         e.printStackTrace();
      }
    this.name = name;//賦值
    this.sex = sex;
    this.flag = true;//改變標識位
    this.notify();//喚醒等待線程
  }
/*同步函數讀取  對象是this*/
  public synchronized void show() {// 同步函數
    if (!flag)
      try {
         this.wait();
      } catch (InterruptedException e) {
         e.printStackTrace();
      }
    System.out.println(this.name + ":" + this.sex);//讀取
    this.flag = false;//改變標識位
    this.notify();//喚醒等待線程
  }
}

/*輸入類*/
public class Input implements Runnable {
  private Res r = null;// 定義了一個資源
 
  public Input(Res r) {// 通過構造方法初始化
    this.r = r;
  }
 
  public void run() {
    int x = 0;
    while (true) {
      if (x == 0) {
         r.set("張三", "男");
      } else {
         r.set("Joney", "female");
      }
      x = (x + 1) % 2;
 
    }
 
  }
}
/*輸出類*/
public class Output implements Runnable {
  private Res r = null;
 
  public Output(Res r) {// 初始化資源
    this.r = r;
  }
 
  public void run() {
    while (true) {
      r.show();
    }
  }
 
}
/*測試類*/
public class Text {
  public static void main(String[] agrs) {
    Res r = new Res();
    new Thread(new Input(r)).start();
    new Thread(new Output(r)).start();
 
  }
}
 


--------------------ASP.Net+Android+IOS開發.Net培訓、期待與您交流! --------------------


發佈了46 篇原創文章 · 獲贊 3 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章