線程之間的通信機制


1.首先我們回顧一下面試題:

兩個線程,一個線程打印1-52,另一個打印字母A-Z打印順序為12A34B...5152Z, 要求用線程間通信

這個面試題就就是完全考察線程之間的通信機制,常用的技術分為二種

  1. 一種是Object 類中的自帶的 wait 和 notify 機制,
  2. 二是 lock中的通信機制 Condition接口中的 await 和 signal 方法。

線程間通信:1、生產者+消費者2、通知等待喚醒機制

  1. Object 類中的自帶的 wait 和 notify 機制實現, synchronized用來辦證線程安全
    package com.atguigu.thread;
     
    import java.util.concurrent.locks.Condition;
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
     
     
     
    class ShareDataOne//資源類
    {
      private int number = 0;//初始值為零的一個變量
     
      public synchronized void increment() throws InterruptedException 
      {
         //1判斷
         if(number !=0 ) {
           this.wait();
         }
         //2干活
         ++number;
         System.out.println(Thread.currentThread().getName()+"\t"+number);
         //3通知
         this.notifyAll();
      }
      
      public synchronized void decrement() throws InterruptedException 
      {
         // 1判斷
         if (number == 0) {
           this.wait();
         }
         // 2干活
         --number;
         System.out.println(Thread.currentThread().getName() + "\t" + number);
         // 3通知
         this.notifyAll();
      }
    }
     
    /**
     * 
     * @Description:
     *現在兩個線程,
     * 可以操作初始值為零的一個變量,
     * 實現一個線程對該變量加1,一個線程對該變量減1,
     * 交替,來10輪。 
     * @author xialei
     *
     *  * 筆記:Java里面如何進行工程級別的多線程編寫
     * 1 多線程變成模板(套路)-----上
     *     1.1  線程    操作    資源類  
     *     1.2  高內聚  低耦合
     * 2 多線程變成模板(套路)-----下
     *     2.1  判斷
     *     2.2  干活
     *     2.3  通知
     
     */
    public class NotifyWaitDemoOne
    {
      public static void main(String[] args)
      {
         ShareDataOne sd = new ShareDataOne();
         new Thread(() -> {
           for (int i = 1; i < 10; i++) {
              try {
                sd.increment();
              } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
              }
           }
         }, "A").start();
         new Thread(() -> {
           for (int i = 1; i < 10; i++) {
              try {
                sd.decrement();
              } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
              }
           }
         }, "B").start();
      }
    }

    注意點:線程通信最好不要用 if 去判斷,用 while 去判斷,因為用 if 去判斷容易造成虛假喚醒,以下是修改之后的數據

    package com.atguigu.thread;
     
    import java.util.concurrent.locks.Condition;
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
     
    import org.omg.IOP.Codec;
     
     
    class ShareData//資源類
    {
      private int number = 0;//初始值為零的一個變量
     
      public synchronized void increment() throws InterruptedException 
      {
         //判斷
         while(number!=0) {
           this.wait();
         }
         //干活
         ++number;
         System.out.println(Thread.currentThread().getName()+" \t "+number);
         //通知
         this.notifyAll();;
      }
      
      public synchronized void decrement() throws InterruptedException 
      {
         //判斷
         while(number!=1) {
           this.wait();
         }
         //干活
         --number;
         System.out.println(Thread.currentThread().getName()+" \t "+number);
         //通知
         this.notifyAll();
      }
    }
     
    /**
     * 
     * @Description:
     *現在兩個線程,
     * 可以操作初始值為零的一個變量,
     * 實現一個線程對該變量加1,一個線程對該變量減1,
     * 交替,來10輪。 
     * @author xialei
     *
     *  * 筆記:Java里面如何進行工程級別的多線程編寫
     * 1 多線程變成模板(套路)-----上
     *     1.1  線程    操作    資源類  
     *     1.2  高內聚  低耦合
     * 2 多線程變成模板(套路)-----下
     *     2.1  判斷
     *     2.2  干活
     *     2.3  通知
     
     */
    public class NotifyWaitDemo
    {
      public static void main(String[] args)
      {
         ShareData sd = new ShareData();
         new Thread(() -> {
     
           for (int i = 1; i <= 10; i++) {
              try {
                sd.increment();
              } catch (InterruptedException e) {
                e.printStackTrace();
              }
           }
         }, "A").start();
         
         new Thread(() -> {
     
           for (int i = 1; i <= 10; i++) {
              try {
                sd.decrement();
              } catch (InterruptedException e) {
                e.printStackTrace();
              }
           }
         }, "B").start();
         new Thread(() -> {
     
           for (int i = 1; i <= 10; i++) {
              try {
                sd.increment();
              } catch (InterruptedException e) {
                e.printStackTrace();
              }
           }
         }, "C").start();
         new Thread(() -> {
     
           for (int i = 1; i <= 10; i++) {
              try {
                sd.decrement();
              } catch (InterruptedException e) {
                e.printStackTrace();
              }
           }
         }, "D").start();
         
      }
    }
     
     
     
     
     
    /*
     * * 
     * 2 多線程變成模板(套路)-----下
     *     2.1  判斷
     *     2.2  干活
     *     2.3  通知
     * 3 防止虛假喚醒用while
     * 
     * 
     * */
     
     
     
     
     
     

     

      使用 Condition去做

package com.atguigu.thread;
 
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
 
import org.omg.IOP.Codec;
 
 
class ShareData//資源類
{
  private int number = 0;//初始值為零的一個變量
 
  private Lock lock = new ReentrantLock();
  private Condition condition  = lock.newCondition(); 
   
  public  void increment() throws InterruptedException 
  {
     
      lock.lock();
         try {
          //判斷
          while(number!=0) {
            condition.await();
          }
          //干活
          ++number;
          System.out.println(Thread.currentThread().getName()+" \t "+number);
          //通知
          condition.signalAll();
     } catch (Exception e) {
       e.printStackTrace();
     } finally {
       lock.unlock();
     }
     
  }
  
  
  public  void decrement() throws InterruptedException 
  {
      
      lock.lock();
         try {
          //判斷
          while(number!=1) {
            condition.await();
          }
          //干活
          --number;
          System.out.println(Thread.currentThread().getName()+" \t "+number);
          //通知
          condition.signalAll();
     } catch (Exception e) {
       e.printStackTrace();
     } finally {
       lock.unlock();
     }
     
  }
  
  /*public synchronized void increment() throws InterruptedException 
  {
     //判斷
     while(number!=0) {
       this.wait();
     }
     //干活
     ++number;
     System.out.println(Thread.currentThread().getName()+" \t "+number);
     //通知
     this.notifyAll();;
  }
  
  public synchronized void decrement() throws InterruptedException 
  {
     //判斷
     while(number!=1) {
       this.wait();
     }
     //干活
     --number;
     System.out.println(Thread.currentThread().getName()+" \t "+number);
     //通知
     this.notifyAll();
  }*/
}
 
/**
 * 
 * @Description:
 *現在兩個線程,
 * 可以操作初始值為零的一個變量,
 * 實現一個線程對該變量加1,一個線程對該變量減1,
 * 交替,來10輪。 
 *
 *  * 筆記:Java里面如何進行工程級別的多線程編寫
 * 1 多線程變成模板(套路)-----上
 *     1.1  線程    操作    資源類  
 *     1.2  高內聚  低耦合
 * 2 多線程變成模板(套路)-----下
 *     2.1  判斷
 *     2.2  干活
 *     2.3  通知
 
 */
public class NotifyWaitDemo
{
  public static void main(String[] args)
  {
     ShareData sd = new ShareData();
     new Thread(() -> {
 
       for (int i = 1; i <= 10; i++) {
          try {
            sd.increment();
          } catch (InterruptedException e) {
            e.printStackTrace();
          }
       }
     }, "A").start();
     
     new Thread(() -> {
 
       for (int i = 1; i <= 10; i++) {
          try {
            sd.decrement();
          } catch (InterruptedException e) {
            e.printStackTrace();
          }
       }
     }, "B").start();
     new Thread(() -> {
 
       for (int i = 1; i <= 10; i++) {
          try {
            sd.increment();
          } catch (InterruptedException e) {
            e.printStackTrace();
          }
       }
     }, "C").start();
     new Thread(() -> {
 
       for (int i = 1; i <= 10; i++) {
          try {
            sd.decrement();
          } catch (InterruptedException e) {
            e.printStackTrace();
          }
       }
     }, "D").start();
     
  }
}
 
 
 
 
 
/*
 * * 
 * 2 多線程變成模板(套路)-----下
 *     2.1  判斷
 *     2.2  干活
 *     2.3  通知
 * 3 防止虛假喚醒用while
 * 
 * 
 * */
 
 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM