<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      JUC并發編程學習筆記(十七)徹底玩轉單例模式

      徹底玩轉單例模式

      單例中最重要的思想------->構造器私有!

      惡漢式、懶漢式(DCL懶漢式?。?/p>

      惡漢式

      package single;
      //餓漢式單例(問題:因為一上來就把對象加載了,所以可能會導致浪費內存)
      public class Hungry {
          /*
          * 如果其中有大量的需要開辟的空間,如new byte[1024*1024]這些,那么一開始就會加載,而不是需要時才加載,所以非常浪費空間
          *
          * */
          private byte[] data1 = new byte[1024*1024];
          private byte[] data2 = new byte[1024*1024];
          private byte[] data3 = new byte[1024*1024];
          private byte[] data4 = new byte[1024*1024];
          private Hungry() {
          }
          private final static Hungry HUNGRY = new Hungry();
      
          public static Hungry getInstance(){
              return HUNGRY;
          }
      }
      

      懶漢式

      DCL懶漢式

      完整的雙重檢測鎖模式的單例、懶漢式、DCL懶漢式

      package single;
      
      public class LazyMan {
          private LazyMan() {
              System.out.println(Thread.currentThread() + "ok");
          }
      
          private volatile static LazyMan lazyMan;
      
          //    單線程下確實ok
          public static LazyMan getInstance() {
      //        加鎖、鎖整個類
      //        雙重檢測鎖模式的單例、懶漢式、DCL懶漢式
              if (lazyMan==null){
                  synchronized (LazyMan.class){
                      if (lazyMan == null) {
                          lazyMan = new LazyMan();//不是原子性操作
      
                      }
                  }
              }
              return lazyMan;
          }
          /*
           * 1、分配內存空間
           * 2、執行構造方法,初始化對象
           * 3、把這個對象指向這個空間
           *
           * 期望的結果:1、2、3
           * 但是由于指令重排可能導致結果為1、3、2,這在cpu中是沒問題的
           * 線程A:1、3、2
           * 線程B如果在線程A執行到3時開始執行判斷是否為null,由于已經占用空間了,所以會被判斷為不為空,但實際還未初始化對象,實際結果還是為null
           *
           *
           * */
      
          //    多線程并發測試
          public static void main(String[] args) {
              for (int i = 0; i < 10; i++) {
                  new Thread(() -> {
                      LazyMan.getInstance();
                  }).start();
              }
          }
      
      }
      

      但是有反射!只要有反射,任何的代碼都不安全,任何的私有關鍵字都是擺設

      正常的單例模式:

      /*
      * 正常的單例模式創建的都為同一個對象,并且該對象全局唯一
      * 只執行一次創建,并且對象都是同一個
      * Thread[main,5,main]ok
      * true
      * */
      LazyMan instance1 = LazyMan.getInstance();
      LazyMan instance2 = LazyMan.getInstance();
      System.out.println(instance2==instance1);
      

      反射破壞單例:

      /*
      * 通過反射破壞單例
      * 執行兩個創建,兩個不同的對象
      * Thread[main,5,main]ok
        Thread[main,5,main]ok
        false
      * */
      LazyMan instance1 = LazyMan.getInstance();
      Constructor<LazyMan> declaredConstructor = LazyMan.class.getDeclaredConstructor();
      declaredConstructor.setAccessible(true);
      LazyMan instance2 = declaredConstructor.newInstance();
      System.out.println(instance2 == instance1);
      

      怎么去解決這種破壞呢?

      首先反射走了無參構造器,我們可以在構造器中進行加鎖判斷是否已經存在了對象。

      private LazyMan() {
          //通過構造器來加鎖判斷防止反射破壞
          synchronized (LazyMan.class){
              if (lazyMan!=null){
                  throw new RuntimeException("不要試圖使用反射破壞單例模式");
              }
          }
      
      }
      

      通過反射破壞單例模式

      道高一尺,魔高一丈

      1、通過普通的反射來破壞單例模式

      Constructor<LazyMan> declaredConstructor = LazyMan.class.getDeclaredConstructor();
      declaredConstructor.setAccessible(true);
      LazyMan lazyMan1 = LazyMan.getInstance();
      LazyMan lazyMan2 = declaredConstructor.newInstance();
      System.out.println(lazyMan1);
      System.out.println(lazyMan2);
      

      解決方法:通過構造器加鎖解決

      private LazyMan() {
          //通過構造器來加鎖判斷防止反射破壞
          synchronized (LazyMan.class){
              if (lazyMan == null){
      
              }else {
                  throw new RuntimeException("不要試圖使用反射破壞單例模式");
              }
      
          }
      }
      

      2、通過反射創建兩個類來破壞單例模式

      Constructor<LazyMan> declaredConstructor = LazyMan.class.getDeclaredConstructor();
      declaredConstructor.setAccessible(true);
      LazyMan lazyMan1 = declaredConstructor.newInstance();
      LazyMan lazyMan2 = declaredConstructor.newInstance();
      System.out.println(lazyMan1);
      System.out.println(lazyMan2);
      

      解決方法:設置一個外部私有變量,在構造方法中通過外部私有變量來操作

      //創建一個外部的標,用于防止通過newInstance破壞單例模式
      private static boolean flg = true;
      private LazyMan() {
          //通過構造器來加鎖判斷防止反射破壞
          synchronized (LazyMan.class){
              if (flg){
                  flg = false;
              }else {
                  throw new RuntimeException("不要試圖使用反射破壞單例模式");
              }
          }
      }
      

      3、通過反射字段來將外部私有變量修改。

      Constructor<LazyMan> declaredConstructor = LazyMan.class.getDeclaredConstructor();
      declaredConstructor.setAccessible(true);
      //通過反射修改內部私有變量
      Field flg1 = LazyMan.class.getDeclaredField("flg");
      flg1.setAccessible(true);
      
      //通過反射的newInstance創建的兩個對象依舊破壞了單例模式
      LazyMan instance1 = declaredConstructor.newInstance();
      //通過反射字段對單例模式進行破壞
      flg1.set(instance1,true);
      LazyMan instance2 = declaredConstructor.newInstance();
      System.out.println(instance2 == instance1);
      

      解決方法,通過枚舉類型!枚舉類型自帶單例模式,禁止反射破壞

      package single;
      
      import java.lang.reflect.Constructor;
      import java.lang.reflect.InvocationTargetException;
      
      //枚舉類
      public enum EnumDemo {
          INSTANCE;
          public EnumDemo getInstance(){
              return INSTANCE;
          }
      }
      class EnumDemoTest{
          public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
              Constructor<EnumDemo> declaredConstructor = EnumDemo.class.getDeclaredConstructor(null);
              declaredConstructor.setAccessible(true);
              EnumDemo enumDemo1 = declaredConstructor.newInstance();
              EnumDemo enumDemo2 = declaredConstructor.newInstance();
              System.out.println(enumDemo1);
              System.out.println(enumDemo2);
          }
      }
      

      發現抱錯,沒有對應的無參構造

      但是idea編譯的源碼中是由無參構造的

      idea欺騙了我們,那么編譯好的類到底有沒有無參構造,通過javap -p反編譯源碼查看所以方法

      可以看到,也有空參的構造方法,也就意味了反編譯源碼也欺騙了你,所以我們通過更專業的工具來查看,使用jad查看。

      查看當前目錄新生成的java文件可以發現,通過jad反編譯的源碼的構造函數時個有參構造函數

      
      // Decompiled by Jad v1.5.8g. Copyright 2001 Pavel Kouznetsov.
      // Jad home page: http://www.kpdus.com/jad.html
      // Decompiler options: packimports(3) 
      // Source File Name:   EnumDemo.java
      
      package single;
      
      
      public final class EnumDemo extends Enum
      {
      public static EnumDemo[] values()
      {
          return (EnumDemo[])$VALUES.clone();
      }
      
      public static EnumDemo valueOf(String name)
      {
          return (EnumDemo)Enum.valueOf(single/EnumDemo, name);
      }
      
      private EnumDemo(String s, int i)
      {
          super(s, i);
      }
      
      public EnumDemo getInstance()
      {
          return INSTANCE;
      }
      
      public static final EnumDemo INSTANCE;
      private static final EnumDemo $VALUES[];
      
      static 
      {
          INSTANCE = new EnumDemo("INSTANCE", 0);
          $VALUES = (new EnumDemo[] {
              INSTANCE
          });
      }
      }
      

      我們嘗試在反射中加入這兩個參數類

      Constructor<EnumDemo> declaredConstructor = EnumDemo.class.getDeclaredConstructor(String.class,int.class);
      

      可以發現,它根據我們預想的結果拋出一個異常

      在newInstance方法中如果時枚舉類就會拋出這個異常,這是從反射層面限制了對枚舉類單例模式的破壞??!

      posted @ 2023-11-09 13:54  高同學,你好  閱讀(85)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 久久毛片少妇高潮| 久久99久久99精品免观看| 少妇又爽又刺激视频| AV免费播放一区二区三区| 天天摸天天操免费播放小视频| 99riav国产精品视频| 手机看片福利一区二区三区 | 波多野结衣久久一区二区| 国产精成人品日日拍夜夜| 久久亚洲色www成人欧美| 久久这里只精品热免费99| 国产精品高清一区二区三区| 丝袜人妻一区二区三区网站| 亚洲国产av无码综合原创国产| 亚洲av色香蕉一二三区| 亚洲最大日韩精品一区| 国产人成视频在线观看| 国产又色又爽又高潮免费| 日本一区二区三区专线| 蜜臀久久综合一本av| 人妻中文字幕亚洲精品| 亚洲产在线精品亚洲第一站一| 日本偷拍自影像视频久久| 色偷偷亚洲女人天堂观看| 日韩区二区三区中文字幕| 亚洲一区二区精品动漫| 中文成人在线| 国内自拍偷拍一区二区三区| 色天天天综合网色天天| 极品尤物被啪到呻吟喷水| 精品 无码 国产观看| 黄色网站免费在线观看| 国产对白老熟女正在播放| 亚洲av二区伊人久久| 色噜噜一区二区三区| 成年无码av片在线蜜芽| 亚洲一级特黄大片在线播放 | 免费久久人人爽人人爽AV| 久久精品国产再热青青青| 你拍自拍亚洲一区二区三区| 国产绿帽在线视频看|