设计模式之单例模式

单例模式

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

懒汉模式

懒汉模式是指该单例模式不会提前创建实例,只有外部调用时才会创建一个实例,好处是 如果使用不到就不会占用内存资源

非线程安全

/**
 * 懒汉模式1,私有化构造器,私有静态变量,提供一个全局访问方法
 *
 * @author leo.z.l
 * @create 2019-11-27  15:31
 */
public class LazyInitializationSingleton {

    private static LazyInitializationSingleton instance;

    private LazyInitializationSingleton() {
    }

    public static LazyInitializationSingleton getInstance() {
        if (instance == null) {
            instance = new LazyInitializationSingleton();
        }
        return instance;
    }
}

线程安全

/**
 * 懒汉式:线程安全的单例模式
 * @author leo.z.l
 * @create 2019-11-27  15:44
 */
public class ThreadSafeSingleton {

    private static ThreadSafeSingleton instance;

    private ThreadSafeSingleton() {
    }

    /**
     * 在方法级加锁,以保证线程安全
     * @return
     */
    public static synchronized ThreadSafeSingleton getInstance(){
        if (instance == null) {
            instance = new ThreadSafeSingleton();
        }
        return instance;
    }
}

DCL

/**
 * 懒汉式:线程安全的双重检查锁单例模式
 *
 * @author leo.z.l
 * @create 2019-11-27  15:49
 */
public class DoubleCheckLazyInitializationSingleton {

    private static DoubleCheckLazyInitializationSingleton instance;

    private DoubleCheckLazyInitializationSingleton() {
    }

    /**
     * 没有在方法级上加锁,而是在内部加锁,提高了效率
     * @return
     */
    public static DoubleCheckLazyInitializationSingleton getInstance() {
        if (instance == null) {
            synchronized (String.class) {
                if (instance == null) {
                    instance = new DoubleCheckLazyInitializationSingleton();
                }
            }
        }
        return instance;
    }
}

静态内部类

effective java 第二版时推荐使用此种方式创建单例,当然,现在也可以使用此种方式创建单例,毕竟枚举不常使用

/**
 * 静态内部类创建单例,缺陷是通过反序列化的方式可以创建多个实例
 * @author leo.z.l
 * @create 2019-11-27  16:27
 */
public class StaticInnerClassSingleton {


    private StaticInnerClassSingleton() {
    }

    /**
     * 使用内部类辅助创建单例,使用final修饰,一旦创建不可更改
     */
    private static class SingletonHelper{
        private static final StaticInnerClassSingleton INSTANCE = new StaticInnerClassSingleton();
    }

    public static StaticInnerClassSingleton getInstance(){
        return SingletonHelper.INSTANCE;
    }
}

饿汉模式

实例在类初始化时就已经创建,如果没有使用,会占用内存资源

枚举单例

  • 在EffectiveJava一书第三版中,推荐使用该方式创建单例模式
  1. 枚举类继承了 java.lang.Enum 其中实现了 Comparable, Serializable
  2. Enum中阻止了默认的序列化方式,则通过传统的序列化方式不会破坏单例模式
/**
 * 单例模式是提供了序列化安全,
 *
 * @author leo.z.l
 * @create 2019-11-27  15:55
 */
public enum EnumSingleton {

    /**
     * 单一的枚举值即为一个单例模式
     */
    SINGLETON;
}

反编译文件

public final class cn.leo.singleton.EnumSingleton extends java.lang.Enum<cn.leo.singleton.EnumSingleton> {
  public static final cn.leo.singleton.EnumSingleton SINGLETON;
  private static final cn.leo.singleton.EnumSingleton[] $VALUES;
  public static cn.leo.singleton.EnumSingleton[] values();
  public static cn.leo.singleton.EnumSingleton valueOf(java.lang.String);
  private cn.leo.singleton.EnumSingleton();
  static {};
}

普通饿汉模式

/**
 * 普通的饿汉模式
 *
 * @author leo.z.l
 * @create 2019-11-27  16:08
 */
public class EagerInitialization {

    private static EagerInitialization instance = new EagerInitialization();

    private EagerInitialization() {
    }

    public static  EagerInitialization getInstance(){
        return instance;
    }
}

静态代码块模式

/**
 * 通过静态代码块进行初始化
 * 
 * @author leo.z.l
 * @create 2019-11-27  16:13
 */
public class StaticBlockSingleton {


    private static StaticBlockSingleton instance;

    static {
        try {
            instance = new StaticBlockSingleton();
        } catch (Exception e) {
            throw new RuntimeException("初始化时异常");
        }
    }

    private StaticBlockSingleton() {
    }

    public static StaticBlockSingleton getInstance() {
        return instance;
    }
}

破坏单例模式

除了枚举实现的单例模式外,其他的方式都有bug,可以通过反射和序列化的方式创建多个实例

反射的方式

/**
 * 使用反射的方式可以创建多个实例 -- 枚举除外
 *
 * @author leo.z.l
 * @create 2019-11-27  16:32
 */
public class ReflectionSingletonTest {

    @Test
    public void doubleCheckLazyInitializationSingletonTest() {
        DoubleCheckLazyInitializationSingleton instanceOne = DoubleCheckLazyInitializationSingleton.getInstance();
        DoubleCheckLazyInitializationSingleton instanceTwo = null;
        try {
            Constructor[] constructors = DoubleCheckLazyInitializationSingleton.class.getDeclaredConstructors();
            for (Constructor constructor : constructors) {
                //Below code will destroy the singleton pattern
                constructor.setAccessible(true);
                instanceTwo = (DoubleCheckLazyInitializationSingleton) constructor.newInstance();
                break;
            }
            System.out.println(instanceOne.hashCode());
            System.out.println(instanceTwo.hashCode());
            System.out.println("doubleCheckLazyInitializationSingletonTest============");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Test
    public void eagerInitializationTest() {
        EagerInitialization instanceOne = EagerInitialization.getInstance();
        EagerInitialization instanceTwo = null;
        try {
            Constructor[] constructors = EagerInitialization.class.getDeclaredConstructors();
            for (Constructor constructor : constructors) {
                //Below code will destroy the singleton pattern
                constructor.setAccessible(true);
                instanceTwo = (EagerInitialization) constructor.newInstance();
                break;
            }
            System.out.println(instanceOne.hashCode());
            System.out.println(instanceTwo.hashCode());
            System.out.println("eagerInitializationTest============");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Test
    public void enumSingletonTest() {
        EnumSingleton instanceOne = EnumSingleton.SINGLETON;
        EnumSingleton instanceTwo = null;
        try {
            Constructor[] constructors = EnumSingleton.class.getDeclaredConstructors();
            for (Constructor constructor : constructors) {
                //Below code will destroy the singleton pattern
                constructor.setAccessible(true);
                instanceTwo = (EnumSingleton) constructor.newInstance();
                break;
            }
            System.out.println(instanceOne.hashCode());
            System.out.println(instanceTwo.hashCode());
            System.out.println("enumSingletonTest============");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Test
    public void lazyInitializationSingletonTest() {
        LazyInitializationSingleton instanceOne = LazyInitializationSingleton.getInstance();
        LazyInitializationSingleton instanceTwo = null;
        try {
            Constructor[] constructors = LazyInitializationSingleton.class.getDeclaredConstructors();
            for (Constructor constructor : constructors) {
                //Below code will destroy the singleton pattern
                constructor.setAccessible(true);
                instanceTwo = (LazyInitializationSingleton) constructor.newInstance();
                break;
            }
            System.out.println(instanceOne.hashCode());
            System.out.println(instanceTwo.hashCode());
            System.out.println("lazyInitializationSingletonTest============");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Test
    public void staticBlockSingletonTest() {
        StaticBlockSingleton instanceOne = StaticBlockSingleton.getInstance();
        StaticBlockSingleton instanceTwo = null;
        try {
            Constructor[] constructors = StaticBlockSingleton.class.getDeclaredConstructors();
            for (Constructor constructor : constructors) {
                //Below code will destroy the singleton pattern
                constructor.setAccessible(true);
                instanceTwo = (StaticBlockSingleton) constructor.newInstance();
                break;
            }
            System.out.println(instanceOne.hashCode());
            System.out.println(instanceTwo.hashCode());
            System.out.println("staticBlockSingletonTest============");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

     @Test
    public void staticInnerClassSingletonTest() {
         StaticInnerClassSingleton instanceOne = StaticInnerClassSingleton.getInstance();
         StaticInnerClassSingleton instanceTwo = null;
        try {
            Constructor[] constructors = StaticInnerClassSingleton.class.getDeclaredConstructors();
            for (Constructor constructor : constructors) {
                //Below code will destroy the singleton pattern
                constructor.setAccessible(true);
                instanceTwo = (StaticInnerClassSingleton) constructor.newInstance();
                break;
            }
            System.out.println(instanceOne.hashCode());
            System.out.println(instanceTwo.hashCode());
            System.out.println("staticInnerClassSingletonTest============");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

     @Test
    public void threadSafeSingletonTest() {
         ThreadSafeSingleton instanceOne = ThreadSafeSingleton.getInstance();
         ThreadSafeSingleton instanceTwo = null;
        try {
            Constructor[] constructors = ThreadSafeSingleton.class.getDeclaredConstructors();
            for (Constructor constructor : constructors) {
                //Below code will destroy the singleton pattern
                constructor.setAccessible(true);
                instanceTwo = (ThreadSafeSingleton) constructor.newInstance();
                break;
            }
            System.out.println(instanceOne.hashCode());
            System.out.println(instanceTwo.hashCode());
            System.out.println("threadSafeSingletonTest============");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

反序列化的方式

/**
 * 使用反序列化的方式可以创建多个实例 -- 枚举除外
 *
 * @author leo.z.l
 * @create 2019-11-27  16:32
 */
public class SerializedSingletonTest {

    @Test
    public void doubleCheckLazyInitializationSingletonTest() {
        try {
            DoubleCheckLazyInitializationSingleton instanceOne = DoubleCheckLazyInitializationSingleton.getInstance();
            ObjectOutput out = new ObjectOutputStream(new FileOutputStream("filename.ser"));
            out.writeObject(instanceOne);
            out.close();

            ObjectInput in = new ObjectInputStream(new FileInputStream("filename.ser"));
            DoubleCheckLazyInitializationSingleton instanceTwo = (DoubleCheckLazyInitializationSingleton) in.readObject();
            in.close();

            System.out.println("instanceOne hashCode=" + instanceOne.hashCode());
            System.out.println("instanceTwo hashCode=" + instanceTwo.hashCode());
            System.out.println("doubleCheckLazyInitializationSingletonTest============");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Test
    public void eagerInitializationTest() {
        try {
            EagerInitialization instanceOne = EagerInitialization.getInstance();
            ObjectOutput out = new ObjectOutputStream(new FileOutputStream("filename.ser"));
            out.writeObject(instanceOne);
            out.close();

            ObjectInput in = new ObjectInputStream(new FileInputStream("filename.ser"));
            EagerInitialization instanceTwo = (EagerInitialization) in.readObject();
            in.close();

            System.out.println("instanceOne hashCode=" + instanceOne.hashCode());
            System.out.println("instanceTwo hashCode=" + instanceTwo.hashCode());
            System.out.println("EagerInitialization============");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Test
    public void enumSingletonTest() {
        try {
            EnumSingleton instanceOne = EnumSingleton.SINGLETON;
            ObjectOutput out = new ObjectOutputStream(new FileOutputStream("filename.ser"));
            out.writeObject(instanceOne);
            out.close();

            ObjectInput in = new ObjectInputStream(new FileInputStream("filename.ser"));
            EnumSingleton instanceTwo = (EnumSingleton) in.readObject();
            in.close();

            System.out.println("instanceOne hashCode=" + instanceOne.hashCode());
            System.out.println("instanceTwo hashCode=" + instanceTwo.hashCode());
            System.out.println("EnumSingleton============");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Test
    public void lazyInitializationSingletonTest() {
        try {
            LazyInitializationSingleton instanceOne = LazyInitializationSingleton.getInstance();
            ObjectOutput out = new ObjectOutputStream(new FileOutputStream("filename.ser"));
            out.writeObject(instanceOne);
            out.close();

            ObjectInput in = new ObjectInputStream(new FileInputStream("filename.ser"));
            LazyInitializationSingleton instanceTwo = (LazyInitializationSingleton) in.readObject();
            in.close();

            System.out.println("instanceOne hashCode=" + instanceOne.hashCode());
            System.out.println("instanceTwo hashCode=" + instanceTwo.hashCode());
            System.out.println("LazyInitializationSingleton============");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Test
    public void staticBlockSingletonTest() {
        try {
            StaticBlockSingleton instanceOne = StaticBlockSingleton.getInstance();
            ObjectOutput out = new ObjectOutputStream(new FileOutputStream("filename.ser"));
            out.writeObject(instanceOne);
            out.close();

            ObjectInput in = new ObjectInputStream(new FileInputStream("filename.ser"));
            StaticBlockSingleton instanceTwo = (StaticBlockSingleton) in.readObject();
            in.close();

            System.out.println("instanceOne hashCode=" + instanceOne.hashCode());
            System.out.println("instanceTwo hashCode=" + instanceTwo.hashCode());
            System.out.println("StaticBlockSingleton============");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Test
    public void staticInnerClassSingletonTest() {
        try {
            StaticInnerClassSingleton instanceOne = StaticInnerClassSingleton.getInstance();
            ObjectOutput out = new ObjectOutputStream(new FileOutputStream("filename.ser"));
            out.writeObject(instanceOne);
            out.close();

            ObjectInput in = new ObjectInputStream(new FileInputStream("filename.ser"));
            StaticInnerClassSingleton instanceTwo = (StaticInnerClassSingleton) in.readObject();
            in.close();

            System.out.println("instanceOne hashCode=" + instanceOne.hashCode());
            System.out.println("instanceTwo hashCode=" + instanceTwo.hashCode());
            System.out.println("StaticInnerClassSingleton============");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Test
    public void threadSafeSingletonTest() {
        try {
            ThreadSafeSingleton instanceOne = ThreadSafeSingleton.getInstance();
            ObjectOutput out = new ObjectOutputStream(new FileOutputStream("filename.ser"));
            out.writeObject(instanceOne);
            out.close();

            ObjectInput in = new ObjectInputStream(new FileInputStream("filename.ser"));
            ThreadSafeSingleton instanceTwo = (ThreadSafeSingleton) in.readObject();
            in.close();

            System.out.println("instanceOne hashCode=" + instanceOne.hashCode());
            System.out.println("instanceTwo hashCode=" + instanceTwo.hashCode());
            System.out.println("ThreadSafeSingleton============");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
posted @ 2019-11-27 17:00  千里暮雲平  阅读(137)  评论(0编辑  收藏  举报