001 单例模式 | 5种实现方式

2019-03-20  本文已影响0人  __destory__

饿汉

public class Singleton {
    private static Singleton instance = new Singleton();
    private Singleton() { }
    public static Singleton getInstance() {
        return instance; 
    }
}

私有化构造函数,创建内部静态对象,通过静态方法返回。
或者如下,一个效果

public class Singleton {
    private static Singleton instance = null;
    static {
        instance = new Singleton();
    }
    private Singleton() { }
    public static Singleton getInstance() {
        return this.instance; 
    }
}

缺点,没有按需求创建对象,导致资源浪费

懒汉

按需生成全局唯一对象

public class Singleton {
    private static Singleton instance = null;
    private Singleton() { }
    public static Synchronized Singleton getInstance() {
          if (instance == null) {
                instance = new Singleton();
          }
        return instance;
    }
}

缺点,Synchronized会导致每次访问,都需要加锁和释放锁,而实际下对象已经有了,何必还这么做,资源浪费。

双重校验

懒汉的变种,提高性能,按需生成对象,后续不需要加锁。

public class Singleton {
    private static Singleton instance = null;
    private Singleton() { }
    public static Singleton getInstance() {
        if (instance == null) { //如果已经初始化,不需要加锁了
            synchronized(Singleton.class) { //未初始化时候会产生竞争,
                if (instance == null) { //第二重校验,为了方式被唤醒的进程再次初始化
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

以上代码,提升性能,但是会有指令重排的问题,指令重排,是JVM优化代码的过程,再不影响最终结果的时候,调整指令执行顺序,这样,会导致双重校验失效,改进,使用volatile

public class Singleton {
    private static volatile Singleton instance = null;
    private Singleton() { }
    public static Singleton getInstance() {
        if (instance == null) {
            synchronized(Singleton.class) {
                if (instance == null){
                    instance = new Singleton();
                }
            }
        }
       return instance; 
    }
}

静态内部类

public class StaticSingleton {
    private StaticSingleton() {}
    private static class SingletonHolder {
        private static StaticSingleton INSTANCE = new StaticSingleton();
    }
    
    public static StaticSingleton  getInstance() {
        return SingletonHolder.INSTANCE;
    }
}

枚举

上述方法虽然可以通过私有化构造函数实现单列,但是通过反射机制,仍然可以强行构造新的对象,StaticSingleton tmp=(StaticSingleton)Class.forName("com.xx.StaticSingleton").newInstance();

因此,使用枚举,可以避免这个

public enum TrafficLamp {
    RED(30) {
         //实现抽象方法
        public TrafficLamp nextLamp() {
            return GREEN;
        }
    },
    GREEN(20) {
        public TrafficLamp nextLamp() {
            return YELLOW;
        }
    },
    YELLOW(10) {
        public TrafficLamp nextLamp() {
            return RED;
        }
    };

    //抽象方法
    public abstract TrafficLamp nextLamp();

    private int time;

    private TrafficLamp(int time) {
        this.time = time;
    }

    public static void main(String[] args) {
        try {
            TrafficLamp tmp=(TrafficLamp)Class.forName("com.roocon.thread.t5.TrafficLamp").newInstance();
        } catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

这里面的,RED GREEN YELLOW 都是单例的,而且,对枚举进行反射会报错,

java.lang.InstantiationException: com.roocon.thread.t5.TrafficLamp
    at java.lang.Class.newInstance(Class.java:427)
    at com.roocon.thread.t5.TrafficLamp.main(TrafficLamp.java:30)
Caused by: java.lang.NoSuchMethodException: com.roocon.thread.t5.TrafficLamp.<init>()
    at java.lang.Class.getConstructor0(Class.java:3082)
    at java.lang.Class.newInstance(Class.java:412)
    ... 1 more
上一篇 下一篇

猜你喜欢

热点阅读