目的
为了方便面试复习, 更倾向于个人学习总结, 学习笔记等.
资源
实现方式
饿汉式
/**
* 单例模式: 饿汉式
*
* @author xiaozhengN 571457082@qq.com
* @since 2022-10-16 12:55:49
**/
public class Singleton1 implements Serializable {
// 饿汉式: 一开始就创建对象
private static final Singleton1 INSTANCE = new Singleton1();
/**
* 构造方法私有化
*/
private Singleton1() {
// 规避反射去破坏单例对象
if (INSTANCE != null) {
throw new RuntimeException("单例对象不能重复创建");
}
System.out.println("私有的无参构造");
}
/**
* 对外提供获取该对象的静态方法
*
* @return 单例对象
*/
public static Singleton1 getInstance() {
return INSTANCE;
}
/**
* 模拟类其他方法
*/
public static void otherMethod() {
System.out.println("对象其他方法");
}
/**
* 对象中重写 readResolve 方法, 规避反序列化破坏单例对象
*
* @return 单例对象
*/
public Object readResolve() {
return INSTANCE;
}
}
枚举饿汉式
/**
* 枚举饿汉式
*
* @author xiaozhengN 571457082@qq.com
* @since 2022-10-16 14:43:15
**/
public enum Singleton2 {
INSTANCE;
// 枚举无参构造默认私用化
Singleton2() {
System.out.println("Singleton2 无参构造方法");
}
@Override
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
/**
* 对外提供获取单例对象方法
*
* @return 单例对象
*/
public static Singleton2 getInstance() {
return INSTANCE;
}
/**
* 模拟其他方法: 主要用于监测是否是饿汉式
*/
public static void otherMethod() {
System.out.println("Singleton2 其他方法");
}
}
懒汉式
/**
* 懒汉式单例
*
* @author xiaozhengN 571457082@qq.com
* @since 2022-10-16 15:55:24
**/
public class Singleton3 implements Serializable {
// 懒加载
private static Singleton3 INSTANCE = null;
// 构造方法私有
private Singleton3() {
// 规避反射去破坏单例对象
if (INSTANCE != null) {
throw new RuntimeException("单例对象不能重复创建");
}
System.out.println("Singleton3 无参构造方法");
}
/**
* 对外提供获取该单例对象的方法
*
* @return 单例对象
*/
public static synchronized Singleton3 getInstance() {
if (INSTANCE == null) {
INSTANCE = new Singleton3();
}
return INSTANCE;
}
/**
* 模拟单例对象其他方法
*/
public static void otherMethod() {
System.out.println("main.daily.Singleton3.otherMethod");
}
/**
* 对象中重写 readResolve 方法, 规避反序列化破坏单例对象
*
* @return 单例对象
*/
public Object readResolve() {
return getInstance();
}
}
双检索懒汉式
/**
* 懒汉式单例-DCL(Double Checked Locked)
*
* @author xiaozhengN 571457082@qq.com
* @since 2022-10-16 16:06:50
**/
public class Singleton4 implements Serializable {
// 懒加载
// 有序性
private static volatile Singleton4 INSTANCE = null;
// 无参构造私有化
private Singleton4() {
if (INSTANCE != null) {
throw new RuntimeException("单例对象不能重复创建");
}
System.out.println("Singleton4 无参构造");
}
/**
* 对外提供获取该单例对象的方法
*
* @return 单例对象
*/
public static Singleton4 getInstance() {
if (INSTANCE == null) {
synchronized (Singleton4.class) {
if (INSTANCE == null) {
INSTANCE = new Singleton4();
}
}
}
return INSTANCE;
}
/**
* 模拟单例对象其他方法
*/
public static void otherMethod() {
System.out.println("main.daily.Singleton4.otherMethod");
}
/**
* 对象中重写 readResolve 方法, 规避反序列化破坏单例对象
*
* @return 单例对象
*/
public Object readResolve() {
return getInstance();
}
}
必须要 volatile, 创建对象, CPU可能会指令重排
17: new #9 // class main/daily/Singleton4
20: dup
21: invokespecial #10 // Method "<init>":()V
24: putstatic #2 // Field INSTANCE:Lmain/daily/Singleton4;
内部类懒汉式
/**
* 懒汉式单例-内部类
*
* @author xiaozhengN 571457082@qq.com
* @since 2022-10-16 16:52:51
**/
public class Singleton5 implements Serializable {
private Singleton5() {
if (Holder.INSTANCE != null) {
throw new RuntimeException("单例对象不能重复创建");
}
System.out.println("Singleton5 无参构造");
}
private static class Holder {
static Singleton5 INSTANCE = new Singleton5();
}
/**
* 对外提供获取该单例对象的方法
*
* @return 单例对象
*/
public static Singleton5 getInstance() {
return Holder.INSTANCE;
}
/**
* 模拟单例对象其他方法
*/
public static void otherMethod() {
System.out.println("main.daily.Singleton5.otherMethod");
}
/**
* 对象中重写 readResolve 方法, 规避反序列化破坏单例对象
*
* @return 单例对象
*/
public Object readResolve() {
return getInstance();
}
}
自验证测试类
/**
* 单例模式测试类
*
* @author xiaozhengN 571457082@qq.com
* @since 2022-10-16 13:14:31
**/
public class TestSingleton {
public static void main(String[] args) throws InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException, IOException, ClassNotFoundException {
System.out.println("------------------------ Singleton1: 饿汉单例开始 ------------------------");
Singleton1.otherMethod();
System.out.println(Singleton1.getInstance());
System.out.println(Singleton1.getInstance());
destroySingletonByReflection(Singleton1.class, Singleton1.getInstance());
destroySingletonBySerializable(Singleton1.getInstance(), Singleton1.getInstance().toString());
destroySingletonByUnsafe(Singleton1.class, Singleton1.getInstance().toString());
System.out.println("------------------------ Singleton1: 饿汉单例结束 ------------------------");
System.out.println("------------------------ Singleton2: 枚举饿汉式开始 ------------------------");
Singleton2.otherMethod();
System.out.println(Singleton2.getInstance());
System.out.println(Singleton2.getInstance());
// 枚举可以自己规避反射去破坏单例
destroySingletonByReflection(Singleton2.class, Singleton2.getInstance());
// 枚举可以自己规避反序列化去破坏单例
destroySingletonBySerializable(Singleton2.getInstance(), Singleton2.getInstance().toString());
destroySingletonByUnsafe(Singleton2.class, Singleton2.getInstance().toString());
System.out.println("------------------------ Singleton2: 枚举饿汉式结束 ------------------------");
System.out.println("------------------------ Singleton3: 懒汉式开始 ------------------------");
Singleton3.otherMethod();
System.out.println(Singleton3.getInstance());
System.out.println(Singleton3.getInstance());
// 枚举可以自己规避反射去破坏单例
destroySingletonByReflection(Singleton3.class, Singleton3.getInstance());
// 枚举可以自己规避反序列化去破坏单例
destroySingletonBySerializable(Singleton3.getInstance(), Singleton3.getInstance().toString());
destroySingletonByUnsafe(Singleton3.class, Singleton3.getInstance().toString());
System.out.println("------------------------ Singleton3: 懒汉式结束 ------------------------");
System.out.println("------------------------ Singleton4: DCL懒汉式开始 ------------------------");
Singleton4.otherMethod();
System.out.println(Singleton4.getInstance());
System.out.println(Singleton4.getInstance());
// 枚举可以自己规避反射去破坏单例
destroySingletonByReflection(Singleton4.class, Singleton4.getInstance());
// 枚举可以自己规避反序列化去破坏单例
destroySingletonBySerializable(Singleton4.getInstance(), Singleton4.getInstance().toString());
destroySingletonByUnsafe(Singleton4.class, Singleton4.getInstance().toString());
System.out.println("------------------------ Singleton4: DCL懒汉式结束 ------------------------");
System.out.println("------------------------ Singleton5: 内部类懒汉式开始 ------------------------");
Singleton5.otherMethod();
System.out.println(Singleton5.getInstance());
System.out.println(Singleton5.getInstance());
// 枚举可以自己规避反射去破坏单例
destroySingletonByReflection(Singleton5.class, Singleton5.getInstance());
// 枚举可以自己规避反序列化去破坏单例
destroySingletonBySerializable(Singleton5.getInstance(), Singleton5.getInstance().toString());
destroySingletonByUnsafe(Singleton5.class, Singleton5.getInstance().toString());
System.out.println("------------------------ Singleton5: 内部类懒汉式结束 ------------------------");
}
// Unsafe 破坏单例
private static void destroySingletonByUnsafe(Class<?> singletonClass, String singletonStr) throws InstantiationException {
Object obj = UnsafeUtils.getUnsafe().allocateInstance(singletonClass);
System.out.println("反序列化是否已经被Unsafe破坏: " + !StrUtil.equals(obj.toString(), singletonStr));
}
// 反序列化破坏单例
private static void destroySingletonBySerializable(Object instance, String singletonStr) throws IOException, ClassNotFoundException {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(instance);
ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(bos.toByteArray()));
String newStr = ois.readObject().toString();
System.out.println("反序列化是否已经被Serializable破坏: " + !StrUtil.equals(newStr, singletonStr));
}
// 反射破坏单例
private static void destroySingletonByReflection(Class<?> singletonClass, Object singletonObj) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
// 通过反射获取私有构造方法
if (singletonObj instanceof Singleton1 || singletonObj instanceof Singleton3 || singletonObj instanceof Singleton4 || singletonObj instanceof Singleton5) {
Constructor<?> declaredConstructor = singletonClass.getDeclaredConstructor();
// 开启访问权限
declaredConstructor.setAccessible(true);
// 执行私有构造方法
String newStr;
try {
newStr = declaredConstructor.newInstance().toString();
System.out.println("单例模式是否已经被Reflection破坏: " + !StrUtil.equals(newStr, singletonObj.toString()));
} catch (Exception e) {
System.out.println("反射破坏单例模式, 已通过抛出异常规避!");
}
}
if (singletonObj instanceof Singleton2) {
Constructor<?> declaredConstructor = singletonClass.getDeclaredConstructor(String.class, int.class);
// 开启访问权限
declaredConstructor.setAccessible(true);
String newStr;
try {
newStr = declaredConstructor.newInstance("OTHER", 3).toString();
System.out.println("单例模式是否已经被Reflection破坏: " + !StrUtil.equals(newStr, singletonObj.toString()));
} catch (Exception e) {
System.out.println("反射破坏枚举单例模式, 已通过抛出异常规避!");
}
}
}
}
自测试结果
------------------------ Singleton1: 饿汉单例开始 ------------------------
私有的无参构造
对象其他方法
main.daily.Singleton1@6ff3c5b5
main.daily.Singleton1@6ff3c5b5
反射破坏单例模式, 已通过抛出异常规避!
反序列化是否已经被Serializable破坏: false
反序列化是否已经被Unsafe破坏: true
------------------------ Singleton1: 饿汉单例结束 ------------------------
------------------------ Singleton2: 枚举饿汉式开始 ------------------------
Singleton2 无参构造方法
Singleton2 其他方法
main.daily.Singleton2@1e80bfe8
main.daily.Singleton2@1e80bfe8
反射破坏枚举单例模式, 已通过抛出异常规避!
反序列化是否已经被Serializable破坏: false
反序列化是否已经被Unsafe破坏: true
------------------------ Singleton2: 枚举饿汉式结束 ------------------------
------------------------ Singleton3: 懒汉式开始 ------------------------
main.daily.Singleton3.otherMethod
Singleton3 无参构造方法
main.daily.Singleton3@79fc0f2f
main.daily.Singleton3@79fc0f2f
反射破坏单例模式, 已通过抛出异常规避!
反序列化是否已经被Serializable破坏: false
反序列化是否已经被Unsafe破坏: true
------------------------ Singleton3: 懒汉式结束 ------------------------
------------------------ Singleton4: DCL懒汉式开始 ------------------------
main.daily.Singleton4.otherMethod
Singleton4 无参构造
main.daily.Singleton4@378fd1ac
main.daily.Singleton4@378fd1ac
反射破坏单例模式, 已通过抛出异常规避!
反序列化是否已经被Serializable破坏: false
反序列化是否已经被Unsafe破坏: true
------------------------ Singleton4: DCL懒汉式结束 ------------------------
------------------------ Singleton5: 内部类懒汉式开始 ------------------------
main.daily.Singleton5.otherMethod
Singleton5 无参构造
main.daily.Singleton5@7c3df479
main.daily.Singleton5@7c3df479
反射破坏单例模式, 已通过抛出异常规避!
反序列化是否已经被Serializable破坏: false
反序列化是否已经被Unsafe破坏: true
------------------------ Singleton5: 内部类懒汉式结束 ------------------------
JDK中体现单例模式的源码
java.lang.Runtime#getRuntime
构造方法私有化
/** Don't let anyone else instantiate this class */
private Runtime() {}
饿汉式单例
private static Runtime currentRuntime = new Runtime();
对外提供获取单例对线的API:
/**
* Returns the runtime object associated with the current Java application.
* Most of the methods of class <code>Runtime</code> are instance
* methods and must be invoked with respect to the current runtime object.
*
* @return the <code>Runtime</code> object associated with the current
* Java application.
*/
public static Runtime getRuntime() {
return currentRuntime;
}
java.lang.System#console
构造方法私有:
/** Don't let anyone instantiate this class */
private System() {
}
Console 对控制台的抽象, volatile 防止CPU指令重排
private static volatile Console cons = null;
获取单例对象API:
/**
* Returns the unique {@link java.io.Console Console} object associated
* with the current Java virtual machine, if any.
*
* @return The system console, if any, otherwise <tt>null</tt>.
*
* @since 1.6
*/
public static Console console() {
if (cons == null) {
synchronized (System.class) {
cons = sun.misc.SharedSecrets.getJavaIOAccess().console();
}
}
return cons;
}
java.util.Collections.EmptySet
public static final Set EMPTY_SET = new EmptySet<>();
private static class EmptySet<E>
extends AbstractSet<E>
implements Serializable
{
private static final long serialVersionUID = 1582296315990362920L;
...
// Preserves singleton property
private Object readResolve() {
return EMPTY_SET;
}
}
java.util.Collections.EmptyList
public static final List EMPTY_LIST = new EmptyList<>();
private static class EmptyList<E>
extends AbstractList<E>
...
// Preserves singleton property
private Object readResolve() {
return EMPTY_LIST;
}
}
java.util.Collections.EmptyMap
public static final Map EMPTY_MAP = new EmptyMap<>();
private static class EmptyMap<K,V>
extends AbstractMap<K,V>
implements Serializable
{
private static final long serialVersionUID = 6428348081105594320L;
...
// Preserves singleton property
private Object readResolve() {
return EMPTY_MAP;
}
}
java.util.Collections.ReverseComparator
ReverseComparator 作为private 内部类, 保证了对其他地方无法创建.
构造方法私有化: 目的就是保证单例对象的唯一性, 其实有没有构造方法无所谓
public class Collections {
...
private static class ReverseComparator
implements Comparator<Comparable<Object>>, Serializable {
private static final long serialVersionUID = 7207038068494060240L;
static final ReverseComparator REVERSE_ORDER
= new ReverseComparator();
public int compare(Comparable<Object> c1, Comparable<Object> c2) {
return c2.compareTo(c1);
}
private Object readResolve() { return Collections.reverseOrder(); }
@Override
public Comparator<Comparable<Object>> reversed() {
return Comparator.naturalOrder();
}
}
...
}
java.util.Comparators.NaturalOrderComparator
/**
* Compares {@link Comparable} objects in natural order.
*
* @see Comparable
*/
enum NaturalOrderComparator implements Comparator<Comparable<Object>> {
INSTANCE;
@Override
public int compare(Comparable<Object> c1, Comparable<Object> c2) {
return c1.compareTo(c2);
}
@Override
public Comparator<Comparable<Object>> reversed() {
return Comparator.reverseOrder();
}
}