设计模式(一)单例模式

饿汉式,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

原文地址:https://www.cnblogs.com/linruitao/p/14970948.html