併發-多線程之間實現通訊

多線程之間實現通訊

多線程之間如何實現通訊

什麼是多線程之間通訊?

   多線程之間通訊,其實就是多個線程在操作同一個資源,但是操作的動作不同。

   畫圖演示

多線程之間通訊需求

  需求:第一個線程寫入(input)用戶,另一個線程取讀取(out)用戶.實現讀一個,寫一個操作。

 

 

代碼實現基本實現

共享資源源實體類

class Res {

     public String userSex;

     public String userName;

}

 

輸入線程資源

class IntThrad extends Thread {

     private Res res;

 

     public IntThrad(Res res) {

          this.res = res;

     }

 

     @Override

     public void run() {

          int count = 0;

          while (true) {

                    if (count == 0) {

                         res.userName = "餘勝軍";

                         res.userSex = "";

                    } else {

                         res.userName = "小紅";

                         res.userSex = "";

                    }

                    count = (count + 1) % 2;

               }

     }

}

 

輸出線程

class OutThread extends Thread {

      private Res res;

 

      public OutThread(Res res) {

            this.res = res;

      }

 

      @Override

      public void run() {

            while (true) {

                       System.out.println(res.userName + "--" + res.userSex);

            }

      }

}

運行代碼

Res res = new Res();

IntThrad intThrad = new IntThrad(res);

OutThread outThread = new OutThread(res);

intThrad.start();

outThread.start();

運行代碼

注意:數據發生錯亂,造成線程安全問題

解決線程安全問題

IntThrad 加上synchronized

class IntThrad extends Thread {

     private Res res;

 

     public IntThrad(Res res) {

          this.res = res;

     }

 

     @Override

     public void run() {

          int count = 0;

          while (true) {

               synchronized (res) {

                    if (count == 0) {

                         res.userName = "餘勝軍";

                         res.userSex = "";

                    } else {

                         res.userName = "小紅";

                         res.userSex = "";

                    }

                    count = (count + 1) % 2;

               }

 

          }

     }

}

輸出線程加上synchronized

class Res {

     public String userName;

     public String sex;

}

 

class InputThread extends Thread {

     private Res res;

 

     public InputThread(Res res) {

          this.res = res;

     }

 

     @Override

     public void run() {

          int count = 0;

          while (true) {

                synchronized (res) {

               if (count == 0) {

                    res.userName = "餘勝軍";

                    res.sex = "";

               } else {

                    res.userName = "小紅";

                    res.sex = "";

               }

               count = (count + 1) % 2;

          }

 

          }

     }

}

 

class OutThrad extends Thread {

     private Res res;

 

     public OutThrad(Res res) {

          this.res = res;

     }

 

     @Override

     public void run() {

          while (true) {

               synchronized (res) {

                    System.out.println(res.userName + "," + res.sex);

               }

          }

 

     }

}

 

public class ThreadDemo01 {

 

     public static void main(String[] args) {

          Res res = new Res();

          InputThread inputThread = new InputThread(res);

          OutThrad outThrad = new OutThrad(res);

          inputThread.start();

          outThrad.start();

     }

 

}

 

 

 

wait、notify方法

 

1.因爲涉及到對象鎖,他們必須都放在synchronized中來使用. Wait、Notify一定要在synchronized裏面進行使用。

2.Wait必須暫定當前正在執行的線程,並釋放資源鎖,讓其他線程可以有機會運行

3. notify/notifyall: 喚醒因鎖池中的線程,使之運行

 

注意:一定要在線程同步中使用,並且是同一個鎖的資源

 

class Res {

     public String userSex;

     public String userName;

     //線程通訊標識

     public boolean flag = false;

}

 

 

class IntThrad extends Thread {

     private Res res;

 

     public IntThrad(Res res) {

          this.res = res;       

     }

 

     @Override

     public void run() {

          int count = 0;

          while (true) {

               synchronized (res) {

                    if (res.flag) {

                         try {

                            // 當前線程變爲等待,但是可以釋放鎖

                              res.wait();

                         } catch (Exception e) {

 

                         }

                    }

                    if (count == 0) {

                         res.userName = "餘勝軍";

                         res.userSex = "";

                    } else {

                         res.userName = "小紅";

                         res.userSex = "";

                    }

                    count = (count + 1) % 2;

                    res.flag = true;

                    // 喚醒當前線程

                    res.notify();

               }

 

          }

     }

}

 

class OutThread extends Thread {

      private Res res;

 

      public OutThread(Res res) {

            this.res = res;

      }

 

      @Override

      public void run() {

            while (true) {

                  synchronized (res) {

                       if (!res.flag) {

                             try {

                                   res.wait();

                             } catch (Exception e) {

                                   // TODO: handle exception

                             }

                       }

                       System.out.println(res.userName + "--" + res.userSex);

                       res.flag = false;

                       res.notify();

                  }

            }

      }

}

 

public class ThreaCommun {

     public static void main(String[] args) {

          Res res = new Res();

          IntThrad intThrad = new IntThrad(res);

          OutThread outThread = new OutThread(res);

          intThrad.start();

          outThread.start();

     }

}

 

wait與sleep區別

對於sleep()方法,我們首先要知道該方法是屬於Thread類中的。而wait()方法,則是屬於Object類中的。

sleep()方法導致了程序暫停執行指定的時間,讓出cpu該其他線程,但是他的監控狀態依然保持者,當指定的時間到了又會自動恢復運行狀態。

在調用sleep()方法的過程中,線程不會釋放對象鎖。

而當調用wait()方法的時候,線程會放棄對象鎖,進入等待此對象的等待鎖定池,只有針對此對象調用notify()方法後本線程才進入對象鎖定池準備

獲取對象鎖進入運行狀態。

 

Lock鎖

在 jdk1.5 之後,併發包中新增了 Lock 接口(以及相關實現類)用來實現鎖功能,Lock 接口提供了與 synchronized 關鍵字類似的同步功能,但需要在使用時手動獲取鎖和釋放鎖。

Lock寫法

Lock lock  = new ReentrantLock();

lock.lock();

try{

//可能會出現線程安全的操作

}finally{

//一定在finally中釋放鎖

//也不能把獲取鎖在try中進行,因爲有可能在獲取鎖的時候拋出異常

  lock.ublock();

}

 

 

Lock與synchronized 關鍵字的區別

Lock 接口可以嘗試非阻塞地獲取鎖 當前線程嘗試獲取鎖。如果這一時刻鎖沒有被其他線程獲取到,則成功獲取並持有鎖。
Lock 接口能被中斷地獲取鎖 與 synchronized 不同,獲取到鎖的線程能夠響應中斷,當獲取到的鎖的線程被中斷時,中斷異常將會被拋出,同時鎖會被釋放。

Lock 接口在指定的截止時間之前獲取鎖,如果截止時間到了依舊無法獲取鎖,則返回。

Condition用法

 Condition的功能類似於在傳統的線程技術中的,Object.wait()和Object.notify()的功能。

代碼

Condition condition = lock.newCondition();

res. condition.await();  類似wait

res. Condition. Signal() 類似notify

 

class Res {

      public String userName;

      public String sex;

      public boolean flag = false;

      Lock lock = new ReentrantLock();

}

 

class InputThread extends Thread {

      private Res res;

      Condition newCondition;

      public InputThread(Res res,  Condition newCondition) {

            this.res = res;

            this.newCondition=newCondition;

      }

 

      @Override

      public void run() {

            int count = 0;

            while (true) {

                  // synchronized (res) {

 

                  try {

                       res.lock.lock();

                       if (res.flag) {

                             try {

//                                 res.wait();

                                   newCondition.await();

                             } catch (Exception e) {

                                   // TODO: handle exception

                             }

                       }

                       if (count == 0) {

                             res.userName = "餘勝軍";

                             res.sex = "";

                       } else {

                             res.userName = "小紅";

                             res.sex = "";

                       }

                       count = (count + 1) % 2;

                       res.flag = true;

//                     res.notify();

                       newCondition.signal();

                  } catch (Exception e) {

                       // TODO: handle exception

                  }finally {

                       res.lock.unlock();

                  }

            }

 

            // }

      }

}

 

class OutThrad extends Thread {

      private Res res;

      private Condition newCondition;

      public OutThrad(Res res,Condition newCondition) {

            this.res = res;

            this.newCondition=newCondition;

      }

 

      @Override

      public void run() {

            while (true) {

//                synchronized (res) {

                  try {

                       res.lock.lock();

                       if (!res.flag) {

                             try {

//                                 res.wait();

                                   newCondition.await();

                             } catch (Exception e) {

                                   // TODO: handle exception

                             }

                       }

                       System.out.println(res.userName + "," + res.sex);

                       res.flag = false;

//                     res.notify();

                       newCondition.signal();

                  } catch (Exception e) {

                       // TODO: handle exception

                  }finally {

                       res.lock.unlock();

                  }

//                }

            }

 

      }

}

 

public class ThreadDemo01 {

 

      public static void main(String[] args) {

            Res res = new Res();

            Condition newCondition = res.lock.newCondition();

            InputThread inputThread = new InputThread(res,newCondition);

            OutThrad outThrad = new OutThrad(res,newCondition);

            inputThread.start();

            outThrad.start();

      }

 

}

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章