设计模式之单例模式

定义:Ensure a class has only one instance, and provide a global point of access to it.(确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。)

1.饿汉式

public class Singleton {

    private static final Singleton INSTANCE = new Singleton();

    private Singleton(){}

    public static Singleton getInstance(){
        return INSTANCE;
    }

    public void method(){
        System.out.println("普通方法");
    }

    public static void main(String[] args) {
        Singleton instance1 = Singleton.getInstance();
        Singleton instance2 = Singleton.getInstance();
        System.out.println(instance1 == instance2);
    }
}

此种方式在工作中最为简单常用。类加载到内存后,就只被实例化一次,所以只会产生一个实例,JVM保证线程安全。唯一的缺点是不管用到与否,都会在类加载的时候完成实例化。

2.懒汉式

public class SingletonLazy {

    private static volatile SingletonLazy INSTANCE;

    private SingletonLazy(){}

    public static SingletonLazy getInstance(){
        if (INSTANCE == null){
            synchronized (Singleton.class){
                if (INSTANCE == null){
                    INSTANCE = new SingletonLazy();
                }
            }
        }
        return INSTANCE;
    }

    public void method(){
        System.out.println("普通方法");
    }

    public static void main(String[] args) {
        for (int i = 0; i < 10; i++) {
            SingletonLazy instance = SingletonLazy.getInstance();
            new Thread(()-> System.out.println(instance.hashCode())).start();
        }
    }
}

此种方式虽然达到了按需初始化的目的,但是带来了线程不安全的问题,所以通过加锁的方式解决,但是又带来效率下降的问题,另外变量需要添加volatile关键字,防止指令重排序。

3.静态内部类

public class SingletonInner {

    private SingletonInner(){}

    private static class SingletonInnerHolder{
        private static final SingletonInner INSTANCE = new SingletonInner();
    }

    public static SingletonInner getInstance(){
        return SingletonInnerHolder.INSTANCE;
    }

    public void method(){
        System.out.println("普通方法");
    }

    public static void main(String[] args) {
        for (int i = 0; i < 10; i++) {
            SingletonInner instance = SingletonInner.getInstance();
            new Thread(()-> System.out.println(instance.hashCode())).start();
        }
    }
}

此种方式解决了上面两种方式的问题,当SingletonInner类被加载的时候,SingletonInnerHolder内部类是不会被加载的,只有在调用getInstance()的时候才会被加载,既达到了懒加载,又保证了只有一个实例。

4.枚举方式

public enum  SingletonEnum {

    INSTANCE;

    public void method(){
        System.out.println("普通方法");
    }

    public static void main(String[] args) {
        for (int i = 0; i < 10; i++) {
            new Thread(()-> 		     System.out.println(SingletonEnum.INSTANCE.hashCode())).start();
        }
    }
}

此种方式不仅可以解决线程同步问题,还可以防止反序列化,因为枚举类没有构造方法。

posted @ 2020-02-29 15:08  TobyHolmes  阅读(196)  评论(0编辑  收藏  举报