• 6.18Java多线程并发、同步性能分析


    6.18Java多线程并发、同步性能分析

    对比同步块和同步方法--->粒度更小的锁定资源,尽可能地提升性能

    根据几个同步锁对象不同的实例观察线程不安全的实例

    package iostudy.synchro;

    /**
    * 测试同步方法和同步块对粒度更小地资源锁定
    * 感受性能上地差异
    * @since JDK 1.8
    * @date 2021/06/18
    * @author Lucifer
    */
    public class SynBlockTestNo3 {
       public static void main(String[] args) {

           /*资源实现类*/
           SynWeb12306 synWeb12306 = new SynWeb12306();

           /*多个线程代理对象*/
           new Thread(synWeb12306, "代劳").start();
           new Thread(synWeb12306, "一楼").start();
           new Thread(synWeb12306, "丙楼").start();

      }
    }

    /**
    * 创建内部资源类
    */
    class SynWeb12306 implements Runnable{

       /*设置资源数量*/
       private int ticketNums = 10;
       private boolean flag = true;

       /*重写接口run方法,实现具体逻辑*/
       @Override
       public void run(){
           while (flag){
               /*模拟线程等待*/
               try {
                   Thread.sleep(100);
              }catch (InterruptedException e){
                   System.out.println(e.getMessage());
                   e.printStackTrace();
              }

               /*调用内部具体实现逻辑的方法*/
               test3();

          }
      }

       /**
        * 写一个内部具体实现逻辑的方法
        * 同步方法
        */
       public synchronized void test1(){
           if (ticketNums<0){
               /*开关改变*/
               flag = false;
               /*结束方法*/
               return;
          }

           /*模拟延时*/
           try {
               Thread.sleep(200);
          }catch (InterruptedException e){
               System.out.println(e.getMessage());
               e.printStackTrace();
          }

           /*获取线程名称、资源数量减少*/
           System.out.println(Thread.currentThread().getName() + "--->" + ticketNums--);

      }

       /**
        * 写另一个一样逻辑的实现方法
        * 同步块
        */
       public void test2(){

           /*明确锁的对象为资源对象*/
           synchronized (this){
               if (ticketNums<0){
                   /*开关改变*/
                   flag = false;
                   /*结束方法*/
                   return;
              }

               /*模拟延时等待*/
               try {
                   Thread.sleep(200);
              }catch (InterruptedException e){
                   System.out.println(e.getMessage());
                   e.printStackTrace();
              }

               /*获取当前线程名称和资源数量*/
               System.out.println(Thread.currentThread().getName() + "--->" + ticketNums--);

          }
      }

       /*只锁定资源*/

       /**
        * 这样锁会不安全,导致数据不准确
        * 原因是因为ticketNums这个资源是会变的,在锁资源的时候大的对象不能变动,里面的资源随便变化
        * 大的对象不变,小的资源对象变。
        * 搞清楚对象在变和对象的属性在变的区别
        */
       public void test3(){

           /*明确锁的对象为资源对象*/
           synchronized ((Integer) ticketNums){
               if (ticketNums<0){
                   /*开关改变*/
                   flag = false;
                   /*结束方法*/
                   return;
              }

               /*模拟延时等待*/
               try {
                   Thread.sleep(200);
              }catch (InterruptedException e){
                   System.out.println(e.getMessage());
                   e.printStackTrace();
              }

               /*获取当前线程名称和资源数量*/
               System.out.println(Thread.currentThread().getName() + "--->" + ticketNums--);

          }
      }
    }

    粒度更小的锁提升性能

    /*只锁定对象的属性--->缩小区域--->还是会有线程不安全问题。范围太小锁不住*/
       /*小粒度锁定资源观察数据是否安全*/
       public void test4(){

           /*只锁定this的ticketNums属性*/
           synchronized (this){
               if (ticketNums<0){
                   /*开关变化*/
                   flag = false;
                   /*结束方法*/
                   return;
              }
          }

           /*模拟网络延迟*/
           try {
               Thread.sleep(200);
          }catch (InterruptedException e){
               System.out.println(e.getMessage());
               e.printStackTrace();
          }

           /*获取当前线程名称以及资源数量*/
           System.out.println(Thread.currentThread().getName() + "--->" + ticketNums--);

      }
    /*锁定范围太大--->损耗性能资源*/
       /**
        * 写另一个一样逻辑的实现方法
        * 同步块
        */
       public void test2(){

           /*明确锁的对象为资源对象*/
           synchronized (this){
               if (ticketNums<0){
                   /*开关改变*/
                   flag = false;
                   /*结束方法*/
                   return;
              }

               /*模拟延时等待*/
               try {
                   Thread.sleep(200);
              }catch (InterruptedException e){
                   System.out.println(e.getMessage());
                   e.printStackTrace();
              }

               /*获取当前线程名称和资源数量*/
               System.out.println(Thread.currentThread().getName() + "--->" + ticketNums--);

          }
      }

    double checking保证数据安全

        /**
        * 写另一个一样逻辑的实现方法
        * 同步块,缩小锁定范围
        */
       public void test5(){

           /*明确锁的对象为资源对象*/
           if (ticketNums<0){
               /*开关改变*/
               flag = false;
               /*结束方法*/
               return;
          }
           /*
           上面的部分考虑的是没有票的情况
           如果有多个线程进来最开始拦截不住还是会出现数据不安全的情况
            */

           /*只锁定下面部分的范围*/
           synchronized (this){
               if (ticketNums<0){
                   /*开关改变*/
                   flag = false;
                   /*结束方法*/
                   return;
              }
               /*
               这里加入判断考虑最后一张票的情况
                */

               /*模拟延时等待*/
               try {
                   Thread.sleep(200);
              }catch (InterruptedException e){
                   System.out.println(e.getMessage());
                   e.printStackTrace();
              }

               /*获取当前线程名称和资源数量*/
               System.out.println(Thread.currentThread().getName() + "--->" + ticketNums--);

          }
           /*
           尽可能地考虑锁合理地范围不是指代码地数量而是指数据地完整性
           --->双重检测(double checking)
           线程安全
           两个检查,第一个检查不用锁定,第二个检查需要锁定
            */
      }

     

    It's a lonely road!!!
  • 相关阅读:
    springcloud+openfeign+naocs实现服务和服务之间灰度调用
    mysql 负数转正数的处理以及java的处理
    ShardingSphereJDBC进行分库分表
    Shell脚本简单示例
    OpenSSL的升级
    Docker使用tomcat部署java项目
    Docker部署node服务
    docker部署Django项目
    delphi TMS FlexCel介绍
    delphi Excel控件介绍
  • 原文地址:https://www.cnblogs.com/JunkingBoy/p/14900984.html
Copyright © 2020-2023  润新知