静态内部类——基于类初始化的延迟加载解决方案
- 创建StaticInnerClassSingleton类
/**
* @author lijiayin
*/
public class StaticInnerClassSingleton {
private StaticInnerClassSingleton(){
}
private static class InnerClass {
private static StaticInnerClassSingleton staticInnerClassSingleton = new StaticInnerClassSingleton();
}
public static StaticInnerClassSingleton getInstance(){
return InnerClass.staticInnerClassSingleton;
}
}
- 创建测试类
/**
* @author lijiayin
*/
public class Test {
public static void main(String[] args) {
Thread t1 = new Thread(() -> {
StaticInnerClassSingleton staticInnerClassSingleton = StaticInnerClassSingleton.getInstance();
System.out.println(Thread.currentThread().getName() + ":" + staticInnerClassSingleton);
});
Thread t2 = new Thread(() -> {
StaticInnerClassSingleton staticInnerClassSingleton = StaticInnerClassSingleton.getInstance();
System.out.println(Thread.currentThread().getName() + ":" + staticInnerClassSingleton);
});
t1.start();
t2.start();
System.out.println("program end");
}
}
-
测试结果
-
类初始化
饿汉式
- 第一种方式
/**
* @author lijiayin
*/
public class HungrySingleton {
private final static HungrySingleton hungrySingleton = new HungrySingleton();
private HungrySingleton(){
}
public static HungrySingleton getInstance(){
return hungrySingleton;
}
}
- 第二种方式
/**
* @author lijiayin
*/
public class HungrySingleton {
private final static HungrySingleton hungrySingleton;
static {
hungrySingleton = new HungrySingleton();
}
private HungrySingleton(){
}
public static HungrySingleton getInstance(){
return hungrySingleton;
}
}
序列化破坏单例模式原理及解决方案
做一个测试
- 修改HungrySingleton类
/**
* @author lijiayin
*/
public class HungrySingleton implements Serializable {
private final static HungrySingleton hungrySingleton;
static {
hungrySingleton = new HungrySingleton();
}
private HungrySingleton(){
}
public static HungrySingleton getInstance(){
return hungrySingleton;
}
}
- 创建测试类
import java.io.*;
/**
* @author lijiayin
*/
public class SerializableTest {
public static void main(String[] args) throws IOException, ClassNotFoundException {
HungrySingleton hungrySingleton = HungrySingleton.getInstance();
ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream("singleton_file"));
outputStream.writeObject(hungrySingleton);
File file = new File("singleton_file");
ObjectInputStream inputStream = new ObjectInputStream(new FileInputStream(file));
HungrySingleton newInstance = (HungrySingleton)inputStream.readObject();
System.out.println(hungrySingleton);
System.out.println(newInstance);
System.out.println(hungrySingleton == newInstance);
}
}
-
测试结果
- 结论与原因
不是相同的对象
4.1 查看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();
}
}
}
4.2 调用了readObject0()方法
private Object readObject0(boolean unshared) throws IOException {
boolean oldMode = bin.getBlockDataMode();
if (oldMode) {
int remain = bin.currentBlockRemaining();
if (remain > 0) {
throw new OptionalDataException(remain);
} else if (defaultDataEnd) {
/*
* Fix for 4360508: stream is currently at the end of a field
* value block written via default serialization; since there
* is no terminating TC_ENDBLOCKDATA tag, simulate
* end-of-custom-data behavior explicitly.
*/
throw new OptionalDataException(true);
}
bin.setBlockDataMode(false);
}
byte tc;
while ((tc = bin.peekByte()) == TC_RESET) {
bin.readByte();
handleReset();
}
depth++;
totalObjectRefs++;
try {
switch (tc) {
case TC_NULL:
return readNull();
case TC_REFERENCE:
return readHandle(unshared);
case TC_CLASS:
return readClass(unshared);
case TC_CLASSDESC:
case TC_PROXYCLASSDESC:
return readClassDesc(unshared);
case TC_STRING:
case TC_LONGSTRING:
return checkResolve(readString(unshared));
case TC_ARRAY:
return checkResolve(readArray(unshared));
case TC_ENUM:
return checkResolve(readEnum(unshared));
case TC_OBJECT:
return checkResolve(readOrdinaryObject(unshared));
case TC_EXCEPTION:
IOException ex = readFatalException();
throw new WriteAbortedException("writing aborted", ex);
case TC_BLOCKDATA:
case TC_BLOCKDATALONG:
if (oldMode) {
bin.setBlockDataMode(true);
bin.peek(); // force header read
throw new OptionalDataException(
bin.currentBlockRemaining());
} else {
throw new StreamCorruptedException(
"unexpected block data");
}
case TC_ENDBLOCKDATA:
if (oldMode) {
throw new OptionalDataException(true);
} else {
throw new StreamCorruptedException(
"unexpected end of block data");
}
default:
throw new StreamCorruptedException(
String.format("invalid type code: %02X", tc));
}
} finally {
depth--;
bin.setBlockDataMode(oldMode);
}
}
4.3 当类型为对象时,调用readOrdinaryObject()方法
private Object readOrdinaryObject(boolean unshared)
throws IOException
{
if (bin.readByte() != TC_OBJECT) {
throw new InternalError();
}
ObjectStreamClass desc = readClassDesc(false);
desc.checkDeserialize();
Class> cl = desc.forClass();
if (cl == String.class || cl == Class.class
|| cl == ObjectStreamClass.class) {
throw new InvalidClassException("invalid class descriptor");
}
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);
}
passHandle = handles.assign(unshared ? unsharedMarker : obj);
ClassNotFoundException resolveEx = desc.getResolveException();
if (resolveEx != null) {
handles.markException(passHandle, resolveEx);
}
if (desc.isExternalizable()) {
readExternalData((Externalizable) obj, desc);
} else {
readSerialData(obj, desc);
}
handles.finish(passHandle);
if (obj != null &&
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;
}
关注这个地方,当类实现了serializable/externalizable时,就会使用反射创建新的对象obj。
obj = desc.isInstantiable() ? desc.newInstance() : null;
4.4 再看一下这里
if (obj != null &&
handles.lookupException(passHandle) == null &&
desc.hasReadResolveMethod())
当对象obj不为空时,查找是否有readResolve()方法;如果有,则通过反射调用这个方法创建对象rep;将反射得到的对象rep赋值给对象obj。
如何解决
- 修改HungrySingleton类
import java.io.Serializable;
/**
* @author lijiayin
*/
public class HungrySingleton implements Serializable {
private final static HungrySingleton hungrySingleton;
static {
hungrySingleton = new HungrySingleton();
}
private HungrySingleton(){
}
public static HungrySingleton getInstance(){
return hungrySingleton;
}
private Object readResolve(){
return hungrySingleton;
}
}
-
测试结果
- 结论
是相同的对象