单例模式
- 单例类只能有一个实例
- 单例类必须自己创建自己的唯一实例。
- 单例类必须给所有其他对象提供这一实例。
常见的几种写法
1 2 3 4 5 6 7 8 9 10 11 12 13
| public class Singleton { private static Singleton instance;
private Singleton() { }
public static Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13
| public class Singleton { private static Singleton instance;
private Singleton() { }
public static synchronized Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; } }
|
> 懒加载,但效率低
1 2 3 4 5 6 7 8 9 10
| public class Singleton { private static Singleton instance = new Singleton();
private Singleton() { }
public static Singleton getInstance() { return instance; } }
|
> 不具备懒加载
1 2 3 4 5 6 7 8 9 10 11 12
| public class Singleton { private Singleton() { }
public static final Singleton getInstance() { return SingletonHolder.INSTANCE; }
private static class SingletonHolder { private static final Singleton INSTANCE = new Singleton(); } }
|
> 懒加载
1 2 3 4 5 6
| public enum Singleton { INSTANCE;
public void whateverMethod() { } }
|
> 推荐
> 能避免多线程同步问题
> 能防止反序列化重新创建新的对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| public class Singleton { private volatile static Singleton singleton;
private Singleton() { }
public static Singleton getSingleton() { if (singleton == null) { synchronized (Singleton.class) { if (singleton == null) { singleton = new Singleton(); } } } return singleton; } }
|
一些扩展
如何破坏单例
- 反射
虽然我们私有
了构造方法,但是反射
仍然能够通过AccessibleObject.setAccessible
访问到私有方法,如:1 2 3 4
| Class clazz = Singleton.class; Constructor cons = clazz.getDeclaredConstructor(null); cons.setAccessible(true); Singleton singleton = (Singleton) cons.newInstance(null);
|
- 反序列化
反序列化通过ObjectInputputStream
来实现,下面来看代码1 2 3 4 5 6 7 8 9 10 11 12
| public final Object readObject() throws IOException, ClassNotFoundException { ... ... int outerHandle = passHandle; try { Object obj = readObject0(false); handles.markDependency(outerHandle, passHandle); ... ... }
|
进入readObject0
方法1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| private Object readObject0(boolean unshared) throws IOException { ... ... try { switch (tc) { case TC_NULL: return readNull(); case TC_REFERENCE: return readHandle(unshared); ... ... case TC_OBJECT: return checkResolve(readOrdinaryObject(unshared)); case TC_EXCEPTION: ... }
|
进入readOrdinaryObject
方法1 2 3 4 5 6 7 8 9 10 11 12 13
| private Object readOrdinaryObject(boolean unshared) throws IOException { ... Object obj; try { obj = desc.isInstantiable() ? desc.newInstance() : null; } catch (Exception ex) { throw (IOException) new InvalidClassException( desc.forClass().getName(),"unable to create instance").initCause(ex); } ... }
|
由此看出,反序列化也是通过反射的方式破坏单例的
防止单例被破坏
- 使用单元素枚举
- 单例类中定义
readResolve
方法
参考
深入理解单例模式(上)
深入理解单例模式(下)