1、若实现了序列化接口,重写readResolve方法即可,反序列化时将调用该方法返回对象实例。
package serialize;
import java.io.*;
public class DoubleCheckLockSerialize{
public static void main(String[] args) throws Exception {
final Singleton instance = Singleton.getInstance();
try (final ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("Singleton.obj"))) {
oos.writeObject(instance);
}
try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream("Singleton.obj"))){
Singleton s2 = (Singleton) ois.readObject();
System.out.println(instance == s2);//true
}
}
}
class Singleton implements Serializable{
private static volatile Singleton INSTANCE;
private Singleton() {
}
public static Singleton getInstance() {
if (INSTANCE == null) {
synchronized (Singleton.class) {
if (INSTANCE == null) {
INSTANCE = new Singleton();
}
}
}
return INSTANCE;
}
/**
* readResolve 用于维护单例行为,如果类实现了反序列化接口,并重写了readResolve()方法时
* JVM会调用类的readResolve()方法获取对象
*/
private Object readResolve() throws ObjectStreamException {
return getInstance();
}
}
2、通过反射破坏单例的场景,可以在构造方法中判断实例是否已经创建,若已创建则抛出异常
package serialize;
import javax.management.InstanceAlreadyExistsException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
public class DoubleCheckLockReflect {
public static void main(String[] args) throws Exception{
for (int i = 0; i < 10; i++) {
new Thread(() -> {
try {
Constructor<Singleton02> declaredConstructor = Singleton02.class.getDeclaredConstructor();
declaredConstructor.setAccessible(true);
final Singleton02 singleton02 = declaredConstructor.newInstance();
System.out.println("反射创建"+singleton02.hashCode());
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (NoSuchMethodException e){
e.printStackTrace();
}
}).start();
}
new Thread(() -> {
try {
final Singleton02 instance = Singleton02.getInstance();
System.out.println("getInstance"+instance.hashCode());
} catch (InstanceAlreadyExistsException e) {
e.printStackTrace();
}
}).start();
}
}
class Singleton02{
private static volatile Singleton02 INSTANCE;
private Singleton02() throws InstanceAlreadyExistsException {
// if (INSTANCE != null){
// throw new InstanceAlreadyExistsException("类实例已存在");
// }
if (INSTANCE == null){
synchronized (Singleton02.class){
if (INSTANCE != null){
throw new InstanceAlreadyExistsException("类实例已存在");
}
}
} else {
throw new InstanceAlreadyExistsException("类实例已存在");
}
}
public static Singleton02 getInstance() throws InstanceAlreadyExistsException {
if (INSTANCE == null) {
synchronized (Singleton02.class) {
if (INSTANCE == null) {
INSTANCE = new Singleton02();
}
}
}
return INSTANCE;
}
}
但是,实际测试结果不如人意,如图,反射在前,getInstance()在后,反射仍然能成功获取实例。
原因是反射在前时,获取实例的过程从始至终都未对INSTANCE变量赋值。
那么如何修改呢?构造函数如下写即可
if (INSTANCE != null){
throw new InstanceAlreadyExistsException("类实例已存在");
} else {
INSTANCE = this;
}
但是会有并发问题。通过双检锁再改
if (INSTANCE == null){
synchronized (Singleton02.class){
if (INSTANCE == null){
INSTANCE = this;
}else {
throw new InstanceAlreadyExistsException("类实例已存在");
}
}
} else {
throw new InstanceAlreadyExistsException("类实例已存在");
}
如下,最终结构:
package serialize;
import javax.management.InstanceAlreadyExistsException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
public class DoubleCheckLockReflect {
public static void main(String[] args) throws Exception{
Thread.sleep(1000);
for (int i = 0; i < 10000; i++) {
new Thread(() -> {
try {
Constructor<Singleton02> declaredConstructor = Singleton02.class.getDeclaredConstructor();
declaredConstructor.setAccessible(true);
final Singleton02 singleton02 = declaredConstructor.newInstance();
System.out.println("反射创建"+singleton02.hashCode());
} catch (InstantiationException e) {
// e.printStackTrace();
} catch (IllegalAccessException e) {
// e.printStackTrace();
} catch (InvocationTargetException e) {
// e.printStackTrace();
} catch (NoSuchMethodException e){
// e.printStackTrace();
}
}).start();
}
new Thread(() -> {
try {
final Singleton02 instance = Singleton02.getInstance();
System.out.println("getInstance"+instance.hashCode());
} catch (InstanceAlreadyExistsException e) {
// e.printStackTrace();
}
}).start();
}
}
class Singleton02{
private static volatile Singleton02 INSTANCE;
private Singleton02() throws InstanceAlreadyExistsException {
if (INSTANCE == null){
synchronized (Singleton02.class){
if (INSTANCE == null){
INSTANCE = this;
}else {
throw new InstanceAlreadyExistsException("类实例已存在");
}
}
} else {
throw new InstanceAlreadyExistsException("类实例已存在");
}
}
public static Singleton02 getInstance() throws InstanceAlreadyExistsException {
if (INSTANCE == null) {
synchronized (Singleton02.class) {
if (INSTANCE == null) {
INSTANCE = new Singleton02();
}
}
}
return INSTANCE;
}
}