线程之间的通信机制

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
 * 
 * 
 * */
 
 

 

posted @ 2020-04-20 09:56  IT路上的小白  阅读(898)  评论(0编辑  收藏  举报