单例模式初衷是为了使资源能够共享,只需要赋值或初始化一次,大家都能够重复利用。
饿汉模式: 在类加载的时候就立即初始化并且创建单例对象。优点是没有加任何锁,执行效率高,绝对线程安全。在用户体验上来说比懒汉模式更好,缺点是一定程度上浪费内存。
懒汉模式: 在需要使用的时候才初始化,不浪费资源,但是线程不安全。
单例模式的七种写法:
1. 饿汉模式,线程安全
public static class Singleton { private final static Singleton INSTANCE = new Singleton(); private Singleton() {} public static Singleton getInstance() { return INSTANCE; } }
2.懒汉模式,线程不安全
public static class Singleton1 { private static Singleton2 instance = null; private Singleton2() {} public static Singleton2 getInstance() { if (instance == null) { instance = new Singleton2(); } return instance; } }
3.懒汉模式,线程安全,多线程环境下效率不高
public static class Singleton2 { private static Singleton2 instance = null; private Singleton2() {} public static synchronized Singleton2 getInstance() { if (instance == null) { instance = new Singleton3(); } return instance; } }
4. 懒汉模式,变种,线程安全
public static class Singleton3 { private static Singleton3 instance = null; static { instance = new Singleton3(); } private Singleton3() {} public static Singleton3 getInstance() { return instance; } }
5. 使用静态内部类,线程安全【推荐】 *内部类在被主类调用的时候才会被加载,这样兼顾了资源问题和线程安全问题*
public static class Singleton4 { private final static class SingleHolder { private static final Singleton4 INSTANCE = new Singleton4(); } private Singleton4(){} public final static Singleton4 getInstance() { return Singleton4Holder.INSTANCE; } }
6. 使用枚举,线程安全【推荐】
public enum class Singleton5 { INSTANCE; }
7. 双重锁
public static class Singleton6 { private volatile static Singleton6 instance = null; private Singleton6(){} public static Singleton6 getInstance() { if(instance == null) { sychronized (Singleton6.class) { if (instance == null) { instance = new Singleton6(); } } } } return instance; }
PS:
1. 防止反射攻击: 加flag:
public static class Singleton6 { private volatile static Singleton6 instance = null; private boolean flag = false; private Singleton6(){
synchronized(Singleton6.class) {
if (flag == false) { flag = !flag; } else { return new RunTimeException("遭遇反射攻击"); }
} } public static Singleton6 getInstance() { if(instance == null) { sychronized (Singleton6.class) { if (instance == null) { instance = new Singleton6(); } } } } return instance; }
2. 防止序列化造成两个实例。写readResolve方法。
public static class Singleton { private final static Singleton INSTANCE = new Singleton(); private Singleton() {} public static Singleton getInstance() { return INSTANCE; } public Object readResolve() { return INSTANCE; } }
3. 附上一个测试实例安全测试方法。使用CountDownLaunch。
public static void main(String[] args) { int count = 200; CountDownLatch latch = new CountDownLatch(count); for (int i = 0; i<count; i++) { new Thread(){ @Override public void run(){ try { latch.await(); } catch (InterruptedException e) { e.printStackTrace(); } Object obj = Factory.getInstance(); System.out.println(System.currentTimeMillis()+ ":" + obj); } }.start(); latch.countDown(); } }
应用场景:
Spring的IOC容器。