单例模式是确保一个类在任何情况下都只有一个实例, 并自行实例化向整个系统提供一个全局的访问点.
/**
* @Author: CaoJun
* @Description: 饿汉式单例模式
* @Create: 2020-01-17 20:09
**/
public class HungrySingleton implements Serializable {
private static final long serialVersionUID = -8686933389819315943L;
/**
* 1. 私有静态实例变量,保证唯一和不被外面置空(饿汉式:一开始就实例化对象)
*/
private static final HungrySingleton HUNGRY_SINGLETON_INSTANCE = new HungrySingleton();
/**
* 2. 私有化构造方法, 防止多个实例产生, 判空(防止反射破坏)
*/
private HungrySingleton() {
if (HUNGRY_SINGLETON_INSTANCE != null) {
throw new RuntimeException("不允许创建多个实例");
}
}
/**
* 3. 公有的静态访问方法, 向整个系统提供全局访问点
*/
public static HungrySingleton getInstance() {
return HUNGRY_SINGLETON_INSTANCE;
}
/**
* 4. 防止序列化: 如果该对象被用于序列化,可以保证对象在序列化前后保持一致
*/
private Object readResolve() {
return HUNGRY_SINGLETON_INSTANCE;
}
}
/**
* @Author: CaoJun
* @Description: 饿汉式静态代码块单例模式
* @Create: 2020-01-17 20:13
**/
public class HungryStaticSingleton implements Serializable {
private static final long serialVersionUID = -4191127512435945546L;
/**
* 1. 私有静态实例变量,保证唯一和不被外面置空(饿汉式:一开始就实例化对象)
*/
private static HungryStaticSingleton HUNGRY_STATIC_SINGLETON_INSTANCE = null;
// 2. 静态代码块实例化
static {
HUNGRY_STATIC_SINGLETON_INSTANCE = new HungryStaticSingleton();
}
/**
* 3. 私有化构造方法, 防止多个实例产生, 判空(防止反射破坏)
*/
private HungryStaticSingleton() {
if (HUNGRY_STATIC_SINGLETON_INSTANCE != null) {
throw new RuntimeException("不允许创建多个实例");
}
}
/**
* 4. 公有的静态访问方法, 向整个系统提供全局访问点
*/
public HungryStaticSingleton getInstance() {
return HUNGRY_STATIC_SINGLETON_INSTANCE;
}
/**
* 5. 防止序列化破坏: 如果该对象被用于序列化,可以保证对象在序列化前后保持一致
*/
private Object readResolve() {
return HUNGRY_STATIC_SINGLETON_INSTANCE;
}
}
/**
* @Author: CaoJun
* @Description: 懒汉式单例模式
* @Create: 2020-01-17 20:16
**/
public class LazySingleton implements Serializable {
private static final long serialVersionUID = 8580274347085357039L;
/**
* 1. 持有私有静态实例,防止被引用,此处赋值为null,目的是实现延迟加载
*/
private static LazySingleton LAZY_SIMPLE_SINGLETON_INSTANCE = null;
/**
* 2. 私有化构造方法, 防止多个实例产生, 判空(防止反射破坏)
*/
private LazySingleton() {
if (LAZY_SIMPLE_SINGLETON_INSTANCE != null) {
throw new RuntimeException("不允许创建多个实例");
}
}
/**
* 3. 公有的静态访问方法, 创建实例, 向整个系统提供全局访问点
*/
public static LazySingleton getInstance() {
// 提高效率
if (LAZY_SIMPLE_SINGLETON_INSTANCE == null) {
// 保证线程安全
synchronized (LazySingleton.class) {
if (LAZY_SIMPLE_SINGLETON_INSTANCE == null) {
LAZY_SIMPLE_SINGLETON_INSTANCE = new LazySingleton();
}
}
}
return LAZY_SIMPLE_SINGLETON_INSTANCE;
}
/**
* 4. 防止序列化: 如果该对象被用于序列化,可以保证对象在序列化前后保持一致
*/
private Object readResolve() {
return LAZY_SIMPLE_SINGLETON_INSTANCE;
}
}
/**
* @Author: CaoJun
* @Description:
* @Create: 2020-01-17 22:04
**/
public class ExecutorThread implements Runnable {
public void run() {
LazySingleton singleton = LazySingleton.getInstance();
System.out.println(Thread.currentThread().getName() + ":" + singleton);
}
}
/**
* @Author: CaoJun
* @Description: LazySingleton 测试
* @Create: 2020-01-17 22:03
**/
public class LazySingletonTest {
public static void main(String[] args) {
Thread t1 = new Thread(new ExecutorThread());
Thread t2 = new Thread(new ExecutorThread());
t1.start();
t2.start();
System.out.println("End");
}
}
/**
* @Author: CaoJun
* @Description: 懒汉式内部类单例模式
* @Create: 2020-01-17 20:21
**/
public class LazyInnerClassSingleton implements Serializable {
private static final long serialVersionUID = -7388698081929929093L;
/**
* 1. 私有化构造方法, 防止多个实例产生, 判空(防止反射破坏)
*/
private LazyInnerClassSingleton() {
if (LazyHolder.LAZY_INNER_CLASS_SINGLETON != null) {
throw new RuntimeException("不允许创建多个实例");
}
}
/**
* 2. 向整个系统提供全局访问点
*/
public static LazyInnerClassSingleton getInstance() {
return LazyHolder.LAZY_INNER_CLASS_SINGLETON;
}
/**
* 3. 此处使用一个内部类来维护单例
*/
private static class LazyHolder {
private static LazyInnerClassSingleton LAZY_INNER_CLASS_SINGLETON = new LazyInnerClassSingleton();
}
/**
* 4. 防止序列化破坏: 如果该对象被用于序列化,可以保证对象在序列化前后保持一致
*/
private Object readResolve() {
return getInstance();
}
}
/**
* @Author: CaoJun
* @Description: 注册式枚举单例模式
* @Create: 2020-01-17 20:30
**/
public enum EnumSingleton {
INSTANCE;
private Object data;
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
public static EnumSingleton getInstance() {
return INSTANCE;
}
}
/**
* @Author: CaoJun
* @Description: 容器缓存方式单例模式
* @Create: 2020-01-17 23:15
**/
public class ContainerSingleton implements Serializable {
private static final long serialVersionUID = -7388698631929929093L;
/**
* 1. 私有化构造方法, 防止多个实例产生, 判空(防止反射破坏)
*/
private ContainerSingleton() {}
/**
* 2. 创建 Map 容器
*/
private static Map<String, Object> ioc = new ConcurrentHashMap<String, Object>();
/**
* 3. 向整个系统提供全局访问点
*/
public static Object getBean(String className) {
synchronized (ioc) {
if (!ioc.containsKey(className)) {
Object obj = null;
try {
obj = Class.forName(className).newInstance();
ioc.put(className, obj);
} catch (Exception e) {
e.printStackTrace();
}
return obj;
} else {
return ioc.get(className);
}
}
}
/**
* 4. 防止序列化破坏: 如果该对象被用于序列化,可以保证对象在序列化前后保持一致
*/
private Object readResolve() {
return getInstance();
}
}
/**
* @Author: CaoJun
* @Description: ThreadLocal 线程单例模式
* @Create: 2020-01-17 20:32
**/
public class ThreadLocalSingleton {
/**
* 1. 使用 ThreadLocal 线程方式创建私有静态实例变量,保证唯一和不被外面置空
*/
private static final ThreadLocal<ThreadLocalSingleton> SINGLETON_THREAD_LOCAL = new ThreadLocal<ThreadLocalSingleton>(){
@Override
protected ThreadLocalSingleton initialValue() {
return new ThreadLocalSingleton();
}
};
/**
* 2. 私有化构造方法, 防止多个实例产生, 判空(防止反射破坏)
*/
private ThreadLocalSingleton() {
if (SINGLETON_THREAD_LOCAL.get() != null) {
throw new RuntimeException("不允许创建多个实例");
}
}
/**
* 3. 公有的静态访问方法, 向整个系统提供全局访问点
*/
public static ThreadLocalSingleton getInstance() {
return SINGLETON_THREAD_LOCAL.get();
}
/**
* 4. 防止序列化破坏: 如果该对象被用于序列化,可以保证对象在序列化前后保持一致
*/
private Object readResolve() {
return getInstance();
}
}
readResolve();
方法可以防止序列化破坏?当我们将一个单例对象创建好,有时候需要将对象序列化然后写入到磁盘,下次使用时再从磁盘中读取到对象,反序列化转化为内存对象。反序列化后的对象会重新分配内存, 即重新创建。那如果序列化的目标的对象为单例对象,就违背了单例模式的初衷,相当 于破坏了单例. 加上 readResolve();
方法可以防止序列化.
源码解释
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
/**
* @author CaoJun
* @Description: 序列化破坏单例模式
* @Create: 2020-01-17 22:36
*/
public class LazySingletonTest {
public static void main(String[] args) {
LazySingleton s1 = null;
LazySingleton s2 = LazySingleton.getInstance();
try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("tmp.obj"));
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("tmp.obj"));) {
oos.writeObject(s2);
oos.flush();
// 进 入 ObjectInputStream 类的 readObject()方法
s1 = (LazySingleton) ois.readObject();
System.out.println(s1 + "\r\n" + s2 + "\r\n" + (s1 == s2));
} catch (Exception e) {
e.printStackTrace();
}
}
}
readObject
中又调用了我们重写的 readObject0()
方法, 进入 readObject0();
方法/**
* ObjectInputStream#readObject()
*/
public final Object readObject()
throws IOException, ClassNotFoundException
{
if (enableOverride) {
return readObjectOverride();
}
// if nested read, passHandle contains handle of enclosing object
int outerHandle = passHandle;
try {
//
Object obj = readObject0(false);
handles.markDependency(outerHandle, passHandle);
ClassNotFoundException ex = handles.lookupException(passHandle);
if (ex != null) {
throw ex;
}
if (depth == 0) {
vlist.doCallbacks();
}
return obj;
} finally {
passHandle = outerHandle;
if (closed && depth == 0) {
clear();
}
}
}
TC_OBJECTD
中判断,调用了 ObjectInputStream#readOrdinaryObject()
方法/**
* ObjectInputStream#readObject0()
*/
private Object readObject0(boolean unshared) throws IOException {
// ......
case TC_OBJECT:
return checkResolve(readOrdinaryObject(unshared));
// ......
}
ObjectStreamClass#isInstantiable()
方法/**
* ObjectStreamClass#readOrdinaryObject()
*/
private Object readOrdinaryObject(boolean unshared)
// ...
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);
}
// ...
if (obj != null &&
// 调用了 hasReadResolveMethod() 方法
handles.lookupException(passHandle) == null &&
desc.hasReadResolveMethod())
{
Object rep = desc.invokeReadResolve(obj);
if (unshared && rep.getClass().isArray()) {
rep = cloneArray(rep);
}
if (rep != obj) {
// Filter the replacement object
if (rep != null) {
if (rep.getClass().isArray()) {
filterCheck(rep.getClass(), Array.getLength(rep));
} else {
filterCheck(rep.getClass(), -1);
}
}
handles.setObject(passHandle, obj = rep);
}
}
return obj;
}
true
/**
* ObjectStreamClass#isInstantiable()
*/
boolean isInstantiable() {
requireInitialized();
return (cons != null);
}
hasReadResolveMethod()
方法, 判断是否为空,不为空就返回 true
boolean hasReadResolveMethod() {
requireInitialized();
return (readResolveMethod != null);
}
readResolve()
方法,并且保存下来/**
* ObjectStreamClass#ObjectStreamClass()
*/
private ObjectStreamClass(final Class<?> cl) {
// ...
readResolveMethod = getInheritableMethod(cl, "readResolve", null, Object.class);
// ...
}
invokeReadResolve()
方法中用反射调用了 readResolveMethod()
方法, 通过 JDK 源码分析我们可以看出,虽然增加 readResolve()
方法返回实例,解决了单例被破坏的问题。但是,我们通过分析源码以及调试,我们可以看到实际上实例化了两次,只不过新创建的对象没有被返回而已, 该对象会被 GC 回收./**
* ObjectStreamClass#invokeReadResolve()
*/
Object invokeReadResolve(Object obj)
throws IOException, UnsupportedOperationException
{
requireInitialized();
if (readResolveMethod != null) {
try {
//
return readResolveMethod.invoke(obj, (Object[]) null);
} catch (InvocationTargetException ex) {
Throwable th = ex.getTargetException();
if (th instanceof ObjectStreamException) {
throw (ObjectStreamException) th;
} else {
throwMiscException(th);
throw new InternalError(th); // never reached
}
} catch (IllegalAccessException ex) {
// should not occur, as access checks have been suppressed
throw new InternalError(ex);
}
} else {
throw new UnsupportedOperationException();
}
}
EnumSingleton.jad
文件。打开 EnumSingleton.jad
文件, 有如下静态代码块: 枚举式单例在静态代码块中就给 INSTANCE 进行了赋值,是饿汉式单例的实现static {
INSTANCE = new EnumSingleton("INSTANCE", 0);
$VALUES = (new EnumSingleton[] { INSTANCE });
}
readObject0()
中调用了 readEnum()
方法,来看 readEnum()
中代码实现/**
* ObjectInputStream#readObject()
*/
private Object readObject0(boolean unshared) throws IOException {
// ...
case TC_ENUM:
return checkResolve(readEnum(unshared)); ...
}
Class
对象类找到一个唯一的枚举对象。因此,枚举对象不可能被类加载器加载多次/**
* ObjectInputStream#readEnum()
*/
private Enum<?> readEnum(boolean unshared) throws IOException {
if (bin.readByte() != TC_ENUM) {
throw new InternalError();
}
ObjectStreamClass desc = readClassDesc(false);
if (!desc.isEnum()) {
throw new InvalidClassException("non-enum class: " + desc);
}
int enumHandle = handles.assign(unshared ? unsharedMarker : null);
ClassNotFoundException resolveEx = desc.getResolveException();
if (resolveEx != null) {
handles.markException(enumHandle, resolveEx);
}
String name = readString(false);
Enum<?> result = null;
Class<?> cl = desc.forClass();
if (cl != null) {
try {
@SuppressWarnings("unchecked")
Enum<?> en = Enum.valueOf((Class)cl, name);
result = en;
} catch (IllegalArgumentException ex) {
throw (IOException) new InvalidObjectException(
"enum constant " + name + " does not exist in " +
cl).initCause(ex);
}
if (!unshared) {
handles.setObject(enumHandle, result);
}
}
handles.finish(enumHandle);
passHandle = enumHandle;
return result;
}
java.lang.NoSuchMethodException
异常, 打开 java.lang.Enum
的源码代码,查看它的构造方法,只有一个 protected
的构造方法/**
* java.lang.Enum
*/
protected Enum(String name, int ordinal) {
this.name = name;
this.ordinal = ordinal;
}
/**
* @Author: CaoJun
* @Description:
* @Create: 2020-01-17 23:10
**/
public class EnumTest {
public static void main(String[] args) {
try {
Class clazz = EnumSingleton.class;
Constructor c = clazz.getDeclaredConstructor(String.class, int.class);
c.setAccessible(true);
EnumSingleton enumSingleton = (EnumSingleton) c.newInstance("Tom", 666);
} catch (Exception e) {
e.printStackTrace();
}
}
}
JDK
源码中的 Constructor#newInstance()
方法中做了强制性的判断,如果修饰符是Modifier.ENUM 枚举类型, 直接抛出异常/**
* Constructor#newInstance()
*/
public T newInstance(Object ... initargs)
throws InstantiationException, IllegalAccessException,
IllegalArgumentException, InvocationTargetException
{
if (!override) {
if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
Class<?> caller = Reflection.getCallerClass();
checkAccess(caller, clazz, null, modifiers);
}
}
if ((clazz.getModifiers() & Modifier.ENUM) != 0)
throw new IllegalArgumentException("Cannot reflectively create enum objects");
ConstructorAccessor ca = constructorAccessor; // read volatile
if (ca == null) {
ca = acquireConstructorAccessor();
}
@SuppressWarnings("unchecked")
T inst = (T) ca.newInstance(initargs);
return inst;
}