What is it?
单例也就是单实例,也就是JVM中只存在一个某类对象,且对外提供一个获取该对象的方法。Where you can use it?
单例使用场景众多,如日志记录对象、JDBC驱动对象 、缓存对象、线程池对象等。在JDK的核心类库中, java.lang.Runtime, java.awt.Desktop等为单例对象,并且 AbstractFactory, Builder, Prototype, Facade等设计模式中也使用单例对象(使用单例模式的思想,也就是融会贯通)。-
How to implement it?
-
private constructor method
- 禁止外部创建对象
-
private static this class instance variable
- 存储该类唯一的对象
-
public method to get this class instance
- 提供给外部获取该单例对象的方法
-
Code Demo
- Eager Initialization
- Class加载时对象已经创建,缺点是无论Client是否使用,对象已经创建
- 无异常处理
public class EagerInitializedSingleton {
private EagerInitializedSingleton() {
}
private static final EagerInitializedSingleton instance = new EagerInitializedSingleton();
public static EagerInitializedSingleton getInstance() {
return instance;
}
}
- Static block initialization
- 增加异常处理
public class StaticBlockSingleton {
private StaticBlockSingleton() {
}
private static StaticBlockSingleton instance;
static {
try {
instance = new StaticBlockSingleton();
} catch (Exception e) {
throw new RuntimeException("exception occured in careating singleton instance.");
}
}
public static StaticBlockSingleton getInstance() {
return instance;
}
}
- Lazy Initialization
- 优点是Client使用时才创建实例
- 缺点是线程不安全
public class LazyInitializedSingletonLazyInitializedSingleton {
private LazyInitializedSingletonLazyInitializedSingleton() {
}
private static LazyInitializedSingletonLazyInitializedSingleton instance;
public static LazyInitializedSingletonLazyInitializedSingleton getInstance() {
if (null == instance) {
instance = new LazyInitializedSingletonLazyInitializedSingleton();
}
return instance;
}
}
- Thread Safe Sigleton
- Client使用时创建
- 线程安全
public class ThreadSafeSingleton {
private ThreadSafeSingleton() {
}
private static ThreadSafeSingleton instance;
public synchronized static ThreadSafeSingleton getInstance() {
if (null == instance) {
instance = new ThreadSafeSingleton();
}
return instance;
}
}
- 双锁校验Thread Safe Singleton
- 只有第一次创建时使用锁
public static ThreadSafeSingleton getInstanceUsingDoubleLocking(){
if (null == instance){
synchronized (ThreadSafeSingleton.class){
if (null == instance){
instance = new ThreadSafeSingleton();
}
}
}
return instance;
}
- Bill Pugh Singleton Implementation
- 使用静态内部类,无需同步锁
- 线程安全
public class BillPughSingleton {
private BillPughSingleton() {
}
private static class SingletonHelper {
private static final BillPughSingleton INSTANCE = new BillPughSingleton();
}
public static BillPughSingleton getInstance() {
return SingletonHelper.INSTANCE;
}
}
-
Using Reflection to destroy Singleton Pattern
- 通过反射可以破坏单例,创建新对象
public class ReflectionSingletonTest {
public static void main(String[] args) {
EagerInitializedSingleton instanceOne = EagerInitializedSingleton.getInstance();
EagerInitializedSingleton instanceTwo = null;
try {
Constructor[] constructors = EagerInitializedSingleton.class.getDeclaredConstructors();
for (Constructor construtor : constructors) {
construtor.setAccessible(true);
instanceTwo = (EagerInitializedSingleton) construtor.newInstance();
}
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(instanceOne.hashCode());
System.out.println(instanceTwo.hashCode());
}
}
- Enum Singleton
- 不灵活
- 不支持懒加载
- 解决反射破坏单例的问题
public enum EnumSingleton {
INSTANCE;
public void doSomething() {
}
}
- Serialization and Singleton
- 反序列化时获取的是新对象
- instanceOne hashCode = 17030099
- instanceTwo hashCode = 3615232
public class SerializedSingleton implements Serializable {
private static final long serialVersionUID = -4535403786288899650L;
private SerializedSingleton() {
}
private static class SingletonHelper {
private static final SerializedSingleton INSTANCE = new SerializedSingleton();
}
public static SerializedSingleton getInstance() {
return SingletonHelper.INSTANCE;
}
}
public class SingletonSerializedTest {
public static void main(String[] args) {
SerializedSingleton instanceOne = SerializedSingleton.getInstance();
try {
ObjectOutput out = new ObjectOutputStream(new FileOutputStream("filename.ser"));
out.writeObject(instanceOne);
ObjectInput in = new ObjectInputStream(new FileInputStream("filename.ser"));
SerializedSingleton instanceTwo = (SerializedSingleton) in.readObject();
System.out.println("instanceOne hashCode = " + instanceOne.hashCode());
System.out.println("instanceTwo hashCode = " + instanceTwo.hashCode());
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
- 序列化破坏单例问题解决方法
- 增加方法readResolve(反序列化时会调用)
- 反序列化时读取的是单例对象不会重新创建新对象
- instanceOne hashCode = 17030099
- instanceTwo hashCode = 17030099
public class SerializedSingleton implements Serializable {
private static final long serialVersionUID = -4535403786288899650L;
private SerializedSingleton() {
}
private static class SingletonHelper {
private static final SerializedSingleton INSTANCE = new SerializedSingleton();
}
public static SerializedSingleton getInstance() {
return SingletonHelper.INSTANCE;
}
protected Object readResolve(){
return getInstance();
}
}