创建单例对象

  • Post author:
  • Post category:其他

注(1): 本文来源:

黑马程序员Java设计模式详解, 23种Java设计模式(图解+框架源码分析+实战)

注(2):本文描述只是粗略描述:方便记忆,如需更加详细讲解:推荐从零开始学习Java设计模式

1. 饿汉式

(1)静态成员变量的方式

/**
 * 饿汉式单例模式==>静态成员变量方式
 * @author hzy
 * @since 2022/10/7
 *
 */
public class Singleton01 {

    private String name;

    //私有构造方法
    private Singleton01(){};

    //在本类中创建对象
    private static final Singleton01 instance = new Singleton01();

    //提供公共的访问方式给外界访问
    public static Singleton01 getInstance(){
        return instance;
    }

    public String getName() {
        return name;
    }

    public Singleton01 setName(String name) {
        this.name = name;
        return this;
    }
}

(2)静态块的方式

/**
 *  饿汉式单例模式==>静态块的方式
 * @author hzy
 * @since 2022/10/7
 */
public class Singleton02 {
    private String name;
    
    //私有构造方法
    private Singleton02(){};

    private static final Singleton02 instance;

    //在静态代码块中赋值
    static {
        instance = new Singleton02();
    }

    public static Singleton02 getInstance(){
        return instance;
    }

    public String getName() {
        return name;
    }

    public Singleton02 setName(String name) {
        this.name = name;
        return this;
    }
}

2. 懒汉式

(1)双重检查锁、指令重排

/**
 * 懒汉单例模式
 * @author hzy
 * @since 2022/10/7
 */
public class LazySingleton04 {
    private String name;
    //私有的构造方法
    private LazySingleton04() {};
    //使用volatile关键字,解决指令重排问题
    private  static volatile LazySingleton04 instance;

    //对外提供访问方式: 加锁,两次检查解决线程安全问题
    public static LazySingleton04 getInstance(){
        if ( instance==null){
            synchronized (LazySingleton04.class){
                if (instance==null){
                    instance = new LazySingleton04();
                }
            }
        }
        return instance;
    }

    public String getName() {
        return name;
    }

    public LazySingleton04 setName(String name) {
        this.name = name;
        return this;
    }
}

使用

   Singleton04 instance = LazySingleton04.getInstance();

(2)枚举方式

/**
 * 懒汉单例模式==>枚举方式创建单例对象
 * @author hzy
 * @since 2022/10/7
 */
public enum LazySingleton06 {
    INSTANCE;
}

(3)静态内部类的方式

/**
 * 懒汉单例模式==>线程安全: 静态内部类的方式创建
 * @author hzy
 * @since 2022/10/7
 */
public class LazySingleton05 {
    private String name;

    private LazySingleton05() {};

    private static class LazySingletonHolder{
        private static final LazySingleton05 INSTANCE = new LazySingleton05();
    }

    public LazySingleton05 getInstance(){
        return LazySingletonHolder.INSTANCE;
    }

    public String getName() {
        return name;
    }

    public LazySingleton05 setName(String name) {
        this.name = name;
        return this;
    }
}

3. 防止单例模式被破坏

(1)防止序列化和反序列化破坏

破坏示例
/**
 * 单例模式破坏: 序列化的方式破坏
 * @author hzy
 * @since 2022/10/7
 */
public class SingletonSerializeDamage {

    public static void main(String[] args) throws Exception {
//        saveObjectToFile();
		//此时我们两次调用方法,返回的对象不是同一个
        getFileObject();
        getFileObject();
    }


    private static void saveObjectToFile() throws Exception{
        Singleton instance = Singleton.getInstance();
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("D:\\single\\single.txt"));
        oos.writeObject(instance);
        oos.close();
    }

    private static void getFileObject() throws Exception{
        ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("D:\\single\\single.txt"));
        Singleton singleton =(Singleton) objectInputStream.readObject();
        System.out.println(singleton);
    }
}

解决:

在该类中添加readResolve()方法

/**
 * @author hzy
 * @since 2022/10/7
 */
public class Singleton implements Serializable {

    private Singleton(){

    };

    private static class SingletonHolder{
        private static final Singleton INSTANCE = new Singleton();
    }

    public  static Singleton getInstance(){
        return SingletonHolder.INSTANCE;
    }
	//加上该方法,在反序列化时,会检查该方法存在性,如果存在,返回该方法的返回值,不存在则创建新对象
    public Object readResolve(){
        return SingletonHolder.INSTANCE;
    }
}

再次执行示例时,两次返回的对象为同一个

(2)反射破坏

破坏示例
/**
 * 单例模式破坏: 反射的方式破坏
 * @author hzy
 * @since 2022/10/7
 */
public class ReflectionDamage {

    public static void main(String[] args) throws Exception {
        //获取字节码对象
        Class<Singleton> singletonClass = Singleton.class;
        //获取无参构造方法
        Constructor<Singleton> declaredConstructor = singletonClass.getDeclaredConstructor();
        //修改构造方法访问权限(因为构造方法是私有的)
        //取消访问检查
        declaredConstructor.setAccessible(true);
        //创建对象
        Singleton singleton = declaredConstructor.newInstance();
        Singleton singleton1 = declaredConstructor.newInstance();
        System.out.println(singleton1==singleton);
    }
}

解决:

在该类的构造方法中加锁,且加判断,是否为第一次创建对象,如果是,则创建新对象,如果不是,则抛出异常

package com.synda.design.patterns.single.damage.reflectionmodel;

import java.io.Serializable;

/**
 * @author hzy
 * @since 2022/10/7
 */
public class Singleton implements Serializable {

    private static boolean flag = false;

    private  Singleton(){
        synchronized (Singleton.class){
            //如果flag是true,则不是第一次创建对象,直接抛出异常
            if (flag){
                throw new RuntimeException("The object exists ");
            }
            flag = true;
        }
    }

    private static class SingletonHolder{
        private static final Singleton INSTANCE = new Singleton();
    }

    public  static Singleton getInstance(){
        return SingletonHolder.INSTANCE;
    }

    public Object readResolve(){
        return SingletonHolder.INSTANCE;
    }
}