单例模式-创建型

单例模式-创建型,第1张

定义:

保证一个类仅有一个实例,并提供一个全局访问点


适应场景:

想确保任何情况下都绝对只有一个实例
如:网站的计数器、线程池、数据库的连接池...


优点:

在内存里只有一个实例,减少了内存开销;
可以避免对资源的多重占用;
设置全局访问点,严格控制访问。


缺点:

没有接口,扩展困难;

重点:

私有构造器;线程安全;延迟加载;序列化和反序列化安全问题(重要);防止反射攻击(重要)。

代码示例: 1.饿汉式

方式1:

package com.demo.design_pattern.creational.singleton;

import java.io.Serializable;

/**
 * HungrySingleton
 *
 * @Description 饿汉式单例模式
 */
public class HungrySingleton implements Serializable {
    // private static final HungrySingleton hungrySingleton = new HungrySingleton();

    private HungrySingleton() {
        //防止单例反射攻击代码
        if (hungrySingleton != null) {
            throw new RuntimeException("单例构造器禁止反射调用");
        }
    }

    public static HungrySingleton getInstance() {
        return hungrySingleton;
    }

    private Object readResolve() {
        return hungrySingleton;
    }
}

方式2:

package com.demo.design_pattern.creational.singleton;

import java.io.Serializable;

/**
 * HungrySingleton
 *
 * @Description 饿汉式单例模式
 */
public class HungrySingleton implements Serializable {
    
    // 放在静态代码块中
    private static HungrySingleton hungrySingleton = null;

    static {
        hungrySingleton = new HungrySingleton();
    }

    private HungrySingleton() {
        //防止单例反射攻击代码
        if (hungrySingleton != null) {
            throw new RuntimeException("单例构造器禁止反射调用");
        }
    }

    public static HungrySingleton getInstance() {
        return hungrySingleton;
    }

    private Object readResolve() {
        return hungrySingleton;
    }
}
2.懒汉式
package com.demo.design_pattern.creational.singleton;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

/**
 * LazySingleton
 *
 * @Description 懒汉式单例模式   注重延迟加载
 */
public class LazySingleton {

    private static LazySingleton lazy = null;

    private LazySingleton() {
        if (lazy != null) {
            throw new RuntimeException("单例构造器禁止反射调用");
        }
    }

    public synchronized static LazySingleton getInstance() {
        if (lazy == null) {
            lazy = new LazySingleton();
        }
        return lazy;
    }


}
3.懒汉式双重校验
package com.demo.design_pattern.creational.singleton;

/**
 * LazyDoubleCheckSingleton
 *
 * @Description 懒汉式双重校验单例模式
 */
public class LazyDoubleCheckSingleton {
    //volatile 保证所有线程可见性
    private volatile static LazyDoubleCheckSingleton lazyDoubleCheckSingleton = null;

    private LazyDoubleCheckSingleton() {
    }

    public static LazyDoubleCheckSingleton getInstance() {
        if (lazyDoubleCheckSingleton == null) {
            synchronized (LazyDoubleCheckSingleton.class) {
                if (lazyDoubleCheckSingleton == null) {
                    lazyDoubleCheckSingleton = new LazyDoubleCheckSingleton();
                    //1.分配内存给这个对象
                    //2.初始化对象
                    //3.设置 lazyDoubleCheckSingleton 指向刚分配的内存地址
                }
            }
        }
        return lazyDoubleCheckSingleton;
    }
}
4.基于容器实现单例模式
package com.demo.design_pattern.creational.singleton;

import org.apache.commons.lang3.StringUtils;

import java.util.HashMap;
import java.util.Map;

/**
 * ContainerSingleton
 *
 * @Description 容器单例模式
 */
public class ContainerSingleton {
    //map看作一个容器
    private static Map singletonMap = new HashMap<>();

    public static void putInstance(String key, Object instance) {
        if (StringUtils.isNotBlank(key) && instance != null) {
            if (!singletonMap.containsKey(key)) {
                singletonMap.put(key, instance);
            }
        }
    }

    public static Object getInstance(String key) {
        return singletonMap.get(key);
    }


}
5.基于枚举实现单例模式
package com.demo.design_pattern.creational.singleton;

/**
 * EnumInstance
 *
 * @Description 使用枚举实现单例模式
 * 主要关注:枚举类型的序列化机制、反射攻击
 */
public enum EnumInstance {
    INSTANCE {
        @Override
        protected void printTest() {
            System.out.println("Geely Print Test");
        }
    };

    protected abstract void printTest();

    private Object data;

    public Object getData() {
        return data;
    }

    public void setData(Object data) {
        this.data = data;
    }

    public static EnumInstance getInstance() {
        return INSTANCE;
    }
}
6.静态内部类单例模式
package com.demo.design_pattern.creational.singleton;

/**
 * StaticInnerClassSingleton
 *
 * @Description 静态内部类单例模式
 */
public class StaticInnerClassSingleton {

    private static class InnerClass {
        private static StaticInnerClassSingleton staticInnerClassSingleton = new StaticInnerClassSingleton();
    }

    public static StaticInnerClassSingleton getInstance() {
        return InnerClass.staticInnerClassSingleton;
    }

    private StaticInnerClassSingleton() {
        if (InnerClass.staticInnerClassSingleton != null) {
            throw new RuntimeException("静态内部类方式 防止反射攻击单例模式");
        }
    }
}
7.基于ThreadLocal的单例模式
package com.demo.design_pattern.creational.singleton;

/**
 * ThreadLocalInstance
 *
 * @Description 基于ThreadLocal的单例模式
 */
public class ThreadLocalInstance {

    private static final ThreadLocal threadLocalInstanceThreadLocal = new ThreadLocal() {

        @Override
        protected ThreadLocalInstance initialValue() {
            return new ThreadLocalInstance();
        }
    };

    private ThreadLocalInstance() {

    }

    public static ThreadLocalInstance getInstance() {
        return threadLocalInstanceThreadLocal.get();
    }


}
8.测试

(1)定义线程类

package com.demo.design_pattern.creational.singleton;

/**
 * MyThread
 *
 * @Description
 */
public class MyThread implements Runnable {
    @Override
    public void run() {
         LazySingleton instance = LazySingleton.getInstance();
        // LazyDoubleCheckSingleton instance =   LazyDoubleCheckSingleton.getInstance();
        //StaticInnerClassSingleton instance =  StaticInnerClassSingleton.getInstance();
        // HungrySingleton instance = HungrySingleton.getInstance();
       /* ContainerSingleton.putInstance("object",new Object());
        Object object = ContainerSingleton.getInstance("object");*/
        //ThreadLocalInstance instance = ThreadLocalInstance.getInstance();
        System.out.println("&&&&&&&&&&&&&&&" + Thread.currentThread().getName() + ":" + instance);
    }
}

(2)测试懒汉式单例模式

package com.demo.design_pattern.creational.singleton;

/**
 * SingletonTest
 *
 * @Description
 */
public class SingletonTest {

    public static void main(String[] args) throws Exception {
         System.out.println("**************测试懒汉式单例模式start");
        // LazySingleton instance = LazySingleton.getInstance();
        //多线程测试懒汉式单例模式
        Thread t1 = new Thread(new MyThread());
        Thread t2 = new Thread(new MyThread());
        t1.start();
        t2.start();
         System.out.println("**************测试懒汉式单例模式end");

    }

}

测试结果

(3)测试 使用序列化或反序列化破坏单例模式

package com.demo.design_pattern.creational.singleton;

import java.io.*;

/**
 * SingletonTest
 *
 * @Description
 */
public class SingletonTest {

    public static void main(String[] args) throws Exception {
    
        //使用序列化或反序列化破坏单例模式
        HungrySingleton hungrySingleton = HungrySingleton.getInstance();
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("singleton_file"));
        oos.writeObject(hungrySingleton);
        File singleton_file = new File("singleton_file");
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(singleton_file));
        HungrySingleton newInstance = (HungrySingleton) ois.readObject();
        System.out.println("!!!!!!!" + hungrySingleton);
        System.out.println("!!!!!!!" + newInstance);
        System.out.println("hungrySingleton == newInstance 为"+ (hungrySingleton == newInstance));
      
    }

}

测试结果:

(4) 饿汉式 反射攻击解决方案

package com.demo.design_pattern.creational.singleton;

import java.io.*;
import java.lang.reflect.Constructor;

/**
 * SingletonTest
 *
 * @Description
 */
public class SingletonTest {

    public static void main(String[] args) throws Exception {
       
        // 饿汉式 反射攻击解决方案
        Class hungrySingletonClass = HungrySingleton.class;
        Constructor constructor = hungrySingletonClass.getDeclaredConstructor();
        constructor.setAccessible(true);
        HungrySingleton instance = HungrySingleton.getInstance();
        HungrySingleton newInstance =(HungrySingleton) constructor.newInstance();
        System.out.println("!!!!!!!" + instance);
        System.out.println("!!!!!!!" + newInstance);
        System.out.println(instance == newInstance);
    
    }

}

(5)静态内部类方式 防止反射攻击

package com.demo.design_pattern.creational.singleton;

import java.io.*;
import java.lang.reflect.Constructor;

/**
 * SingletonTest
 *
 * @Description
 */
public class SingletonTest {

    public static void main(String[] args) throws Exception {
       
        //静态内部类方式 防止反射攻击
        Class staticInnerClassSingletonClass = StaticInnerClassSingleton.class;
        Constructor constructor = staticInnerClassSingletonClass.getDeclaredConstructor();
        constructor.setAccessible(true);
        StaticInnerClassSingleton newInstance = (StaticInnerClassSingleton)constructor.newInstance();
        StaticInnerClassSingleton instance = StaticInnerClassSingleton.getInstance();
    
    }

}

(6)使用懒汉式 防止反射攻击

package com.demo.design_pattern.creational.singleton;

import java.io.*;
import java.lang.reflect.Constructor;

/**
 * SingletonTest
 *
 * @Description
 */
public class SingletonTest {

    public static void main(String[] args) throws Exception {
       
        //使用懒汉式 防止反射攻击
        Class objectClass = LazySingleton.class;
        Constructor constructor = objectClass.getDeclaredConstructor();
        constructor.setAccessible(true);
        LazySingleton newInstance = (LazySingleton)constructor.newInstance();
        LazySingleton instance =  LazySingleton.getInstance();
        System.out.println("!!!!!!!" + instance);
        System.out.println("!!!!!!!" + newInstance);
        System.out.println(instance == newInstance);
    
    }

}

测试结果:

(7)枚举测试序列化机制

package com.demo.design_pattern.creational.singleton;

import java.io.*;
import java.lang.reflect.Constructor;

/**
 * SingletonTest
 *
 * @Description
 */
public class SingletonTest {

    public static void main(String[] args) throws Exception {
       //枚举测试序列化机制
        EnumInstance enumInstance = EnumInstance.getInstance();
        enumInstance.setData(new Object());
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("singleton_file"));
        oos.writeObject(enumInstance);
        File singleton_file = new File("singleton_file");
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(singleton_file));
        EnumInstance newInstance = (EnumInstance) ois.readObject();
        System.out.println("!!!!!!!" + enumInstance.getData());
        System.out.println("!!!!!!!" + newInstance.getData());
        System.out.println(enumInstance.getData() == newInstance.getData());
    
    }

}

测试结果:

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/721846.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-04-25
下一篇 2022-04-25

发表评论

登录后才能评论

评论列表(0条)

保存