• JUC-线程间通信


    面试题:

    两个线程,一个线程打印1-52,另一个打印字母A-Z打印顺序为12A34B...5152Z, 

    要求用线程间通信

    线程间通信:1、生产者+消费者2、通知等待唤醒机制

    多线程编程模版中

    1、判断

    2、干活

    3、唤醒

    synchronized实现

    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 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()+"	"+number);
         //3通知
         this.notifyAll();
      }
      
      public synchronized void decrement() throws InterruptedException 
      {
         // 1判断
         if (number == 0) {
           this.wait();
         }
         // 2干活
         --number;
         System.out.println(Thread.currentThread().getName() + "	" + 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();
      }
    }
    /*
     * * 
     * 2 多线程变成模板(套路)-----下
     *     2.1  判断
     *     2.2  干活
     *     2.3  通知
     * 3 防止虚假唤醒用while
     * 
     * 
     * */
     

    换成4个线程会导致错误,虚假唤醒 

      

    原因:在java多线程判断时,不能用if,程序出事出在了判断上面, 

    突然有一添加的线程进到if了,突然中断了交出控制权, 

    没有进行验证,而是直接走下去了,加了两次,甚至多次

    解决虚假唤醒:查看API,java.lang.Object 

    mmnotes://1.png

    中断和虚假唤醒是可能产生的,所以要用loop循环,if只判断一次,while是只要唤醒就要拉回来再判断一次。if换成while

    java8实现

    mmnotes://0.png

    Condition:查看API,java.util.concurrent 
     
     
    class BoundedBuffer {
       final Lock lock = new ReentrantLock();
       final Condition notFull  = lock.newCondition(); 
       final Condition notEmpty = lock.newCondition(); 
    

       final Object[] items = new Object[100];
       int putptr, takeptr, count;
    

       public void put(Object x) throws InterruptedException {
         lock.lock();
         try {
           while (count == items.length)
             notFull.await();
           items[putptr] = x;
           if (++putptr == items.length) putptr = 0;
           ++count;
           notEmpty.signal();
         } finally {
           lock.unlock();
         }
       }
     

    mmnotes://0.png

     线程间定制化调用通信

    package com.atguigu.thread;
    

    import java.util.concurrent.locks.Condition;
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
    

    

    class ShareResource
    {
      private int number = 1;//1:A 2:B 3:C 
      private Lock lock = new ReentrantLock();
      private Condition c1 = lock.newCondition();
      private Condition c2 = lock.newCondition();
      private Condition c3 = lock.newCondition();
    

      public void print5(int totalLoopNumber)
      {
         lock.lock();
         try 
         {
           //1 判断
           while(number != 1)
           {
              //A 就要停止
              c1.await();
           }
           //2 干活
           for (int i = 1; i <=5; i++) 
           {
              System.out.println(Thread.currentThread().getName()+"	"+i+"	 totalLoopNumber: "+totalLoopNumber);
           }
           //3 通知
           number = 2;
           c2.signal();
         } catch (Exception e) {
           e.printStackTrace();
         } finally {
           lock.unlock();
         }
      }
      public void print10(int totalLoopNumber)
      {
         lock.lock();
         try 
         {
           //1 判断
           while(number != 2)
           {
              //A 就要停止
              c2.await();
           }
           //2 干活
           for (int i = 1; i <=10; i++) 
           {
              System.out.println(Thread.currentThread().getName()+"	"+i+"	 totalLoopNumber: "+totalLoopNumber);
           }
           //3 通知
           number = 3;
           c3.signal();
         } catch (Exception e) {
           e.printStackTrace();
         } finally {
           lock.unlock();
         }
      }  
      
      public void print15(int totalLoopNumber)
      {
         lock.lock();
         try 
         {
           //1 判断
           while(number != 3)
           {
              //A 就要停止
              c3.await();
           }
           //2 干活
           for (int i = 1; i <=15; i++) 
           {
              System.out.println(Thread.currentThread().getName()+"	"+i+"	 totalLoopNumber: "+totalLoopNumber);
           }
           //3 通知
           number = 1;
           c1.signal();
         } catch (Exception e) {
           e.printStackTrace();
         } finally {
           lock.unlock();
         }
      }  
    }
    

    

    /**
     * 
     * @Description: 
     * 多线程之间按顺序调用,实现A->B->C
     * 三个线程启动,要求如下:
     * 
     * AA打印5次,BB打印10次,CC打印15次
     * 接着
     * AA打印5次,BB打印10次,CC打印15次
     * ......来10轮  
     * @author xialei
     *
     */
    public class ThreadOrderAccess
    {
      public static void main(String[] args)
      {
         ShareResource sr = new ShareResource();
         
         new Thread(() -> {
           for (int i = 1; i <=10; i++) 
           {
              sr.print5(i);
           }
         }, "AA").start();
         new Thread(() -> {
           for (int i = 1; i <=10; i++) 
           {
              sr.print10(i);
           }
         }, "BB").start();
         new Thread(() -> {
           for (int i = 1; i <=10; i++) 
           {
              sr.print15(i);
           }
         }, "CC").start();   
         
         
      }
    }
    

  • 相关阅读:
    Procedure execution failed 2013
    struts2总结四:Action与Form表单的交互
    JQuery中的DOM操作
    easyui提交表单数据的时候如何防止二次提交
    一句话
    字符串截取函数substr和substring的不同及其相关说明
    四句话
    JAVA定时执行任务,每天定时几点钟执行任务
    JAVA定时执行任务的三种方法
    struts2总结三:struts2配置文件struts.xml的简单总结
  • 原文地址:https://www.cnblogs.com/minmin123/p/11412601.html
Copyright © 2020-2023  润新知