zoukankan      html  css  js  c++  java
  • 设计模式(一)单例模式

    饿汉式,DCL懒汉式

    1、饿汉式单例

    /**
     * 饿汉式单例
     * @author it-小林
     * @date 2021年07月05日 9:05
     */
    public class HungryPattern {
    
        //可能会浪费空间,开辟了空间,却没有使用
        private HungryPattern(){
    
        }
    
        private final static HungryPattern hungryPattern = new HungryPattern();
    
        public final HungryPattern getInstance(){
            return hungryPattern;
        }
    }

    2、饿汉式单例

    (1)存在多线程并发模式,也就是说多线程模式下,会有问题。

     1 /**
     2  * @author it-小林
     3  * @date 2021年07月05日 9:11
     4  */
     5 public class LazyPattern {
     6 
     7     private LazyPattern() {
     8 
     9     }
    10 
    11     private static LazyPattern lazyPattern;
    12 
    13     private static LazyPattern getInstance(){
    14         if(lazyPattern == null){
    15             lazyPattern = new LazyPattern();
    16         }
    17         return lazyPattern;
    18     }
    19 
    20     //多线程开发
    21     public static void main(String[] args) {
    22         Thread thread1 = new Thread(){
    23             @Override
    24             public void run() {
    25                 System.out.println(LazyPattern.getInstance());
    26             }
    27         };
    28         thread1.start();
    29         Thread thread2 = new Thread(){
    30             @Override
    31             public void run() {
    32                 System.out.println(LazyPattern.getInstance());
    33             }
    34         };
    35         thread2.start();
    36     }
    37 }

    (2)双重检测锁模式的 懒汉式单例  DCL懒汉式

    注意:synchronized 解决并发问题,但是因为lazyMan = new LazyMan();不是原子性操作(可以分割,见代码注释),可能发生指令重排序的问题,通过volatil来解决。

    • Java 语言提供了 volatile和 synchronized 两个关键字来保证线程之间操作的有序性,volatile 是因为其本身包含“禁止指令重排序”的语义,synchronized 是由“一个变量在同一个时刻只允许一条线程对其进行 lock 操作”这条规则获得的,此规则决定了持有同一个对象锁的两个同步块只能串行执行;

    • 原子性就是指该操作是不可再分的。不论是多核还是单核,具有原子性的量,同一时刻只能有一个线程来对它进行操作。简而言之,在整个操作过程中不会被线程调度器中断的操作,都可认为是原子性。比如 a = 1。
    /**
     * @author it-小林
     * @date 2021年07月05日 9:11
     */
    public class LazyPattern {
    
        private LazyPattern() {
    
        }
    
        private static LazyPattern lazyPattern;
    
        //双重检测模式的  懒汉式单例   DCL懒汉式
        private static LazyPattern getInstance(){
            if(lazyPattern == null){
                synchronized (LazyPattern.class){
                    if(lazyPattern == null){
                        //不是一个原子性操作
                        lazyPattern = new LazyPattern();
                        /**
                         * 1.分配内存空间
                         * 2、执行构造方法,初始化对象
                         * 3、把这个对象指向这个空间
                         */
                    }
                }
            }
    
            return lazyPattern;
        }
    
        //多线程开发
        public static void main(String[] args) {
            Thread thread1 = new Thread(){
                @Override
                public void run() {
                    System.out.println(LazyPattern.getInstance());
                }
            };
            thread1.start();
            Thread thread2 = new Thread(){
                @Override
                public void run() {
                    System.out.println(LazyPattern.getInstance());
                }
            };
            thread2.start();
        }
    }

    3、静态内部类

     1 /**
     2  * 静态内部类
     3  * @author it-小林
     4  * @date 2021年07月05日 19:29
     5  */
     6 public class Holder {
     7 
     8     //构造器私有
     9     public Holder() {
    10 
    11     }
    12 
    13     public static Holder getInstance(){
    14         return InnerClass.HOLDER;
    15     }
    16 
    17     public static class InnerClass{
    18         private static final Holder HOLDER = new Holder();
    19     }
    20 
    21 }

     4、单例不安全,反射破坏(见注释及main方法中反射破解步骤)

     1 /**
     2  * @author 林瑞涛
     3  * @date 2021年07月05日 9:11
     4  */
     5 public class LazyPattern {
     6 
     7     //红绿等解决通过反射创建对象(反编译可以破解该方法)
     8     private static boolean bolNew = false;
     9     private LazyPattern() {
    10         synchronized (LazyPattern.class){
    11             if(bolNew == false){
    12                 bolNew = true;
    13             }else{
    14                 throw new RuntimeException("不要试图使用反射破坏单例");
    15             }
    16         }
    17     }
    18 
    19     //volatile避免指令重排
    20     private volatile static LazyPattern lazyPattern;
    21 
    22 
    23     //双重检测模式的  懒汉式单例   DCL懒汉式
    24     private static LazyPattern getInstance(){
    25 
    26         if(lazyPattern == null){
    27             //不是一个原子性操作
    28             lazyPattern = new LazyPattern();
    29         }
    30         return lazyPattern;
    31     }
    32 
    33     //反射
    34     public static void main(String[] args) throws NoSuchFieldException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
    35         Field bolNew = LazyPattern.class.getDeclaredField("bolNew");
    36         bolNew.setAccessible(true);
    37 
    38         Constructor<LazyPattern> declaredConstructor = LazyPattern.class.getDeclaredConstructor(null);
    39         declaredConstructor.setAccessible(true);//无视私有的构造器
    40         LazyPattern instance1 = declaredConstructor.newInstance();
    41         bolNew.set(instance1,false);
    42         System.out.println(instance1);
    43         LazyPattern instance2 = declaredConstructor.newInstance();
    44 
    45         System.out.println(instance2);
    46     }
    47 }

    枚举:通过反射破解枚举发现不成功:
    1、普通的反编译会欺骗开发者,说enum枚举是无参构造
    2、实际enum为有参构造(见后面);
    3、通过反射破解枚举会发现抛出异常
    Exception in thread "main" java.lang.IllegalArgumentException: Cannot reflectively create enum objects at java.lang.reflect.Constructor.newInstance(Constructor.java:417) at com.ph.single.Test.main(EnumSingle.java:19)

     1 //enmu是什么?本身也是一个class类
     2 public enum EnumSingle {
     3     INSTANCE;
     4     public EnumSingle getInstance(){
     5         return INSTANCE;
     6     }
     7 }
     8 
     9 class Test{
    10     public static void main(String[] args) throws Exception {
    11         EnumSingle instance = EnumSingle.INSTANCE;
    12         Constructor<EnumSingle> declaredConstructor = EnumSingle.class.getDeclaredConstructor(String.class,int.class);
    13         declaredConstructor.setAccessible(true);
    14         EnumSingle instance2 = declaredConstructor.newInstance();
    15 
    16         //java.lang.NoSuchMethodException: com.ph.single.EnumSingle.<init>()
    17         System.out.println(instance);
    18         System.out.println(instance2);
    19 
    20     }
    21 }

    通过idea和jdk自带的反编译枚举如下:

     

    通过JDK反编译枚举的代码如下,  发现枚举其实是有参构造

    如本文有侵权行为,请及时与本人联系,多多包涵! 小生初出茅庐,多多指教!

    本文来自博客园,作者:it-小林,转载请注明原文链接:https://www.cnblogs.com/linruitao/p/14970948.html

  • 相关阅读:
    转:Git: git stash 用法小结
    Checkbox: ListView 与CheckBox 触发事件冲突的问题
    android: getDimension, getDimensionPixelOffset 和getDimensionPixelSize 区别
    java: 保留两位小数4种方法
    java: 保留两位小数4种方法
    转:在eclipse中 使用7.0及以上手机进行测试时logcat不打印日志的解决办法
    转:Android文件存储路径getFilesDir()与getExternalFilesDir的区别
    Gradle-修改.gradle默认目录
    Windows: 打开关闭网络连接的方法
    dom4j: 生成XML时文本中回车换行无效
  • 原文地址:https://www.cnblogs.com/linruitao/p/14970948.html
Copyright © 2011-2022 走看看