单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。
注意:
- 1、单例类只能有一个实例。
- 2、单例类必须自己创建自己的唯一实例。
- 3、单例类必须给所有其他对象提供这一实例。
整体大纲
1、代码实现
1.1 饿汉式-1
静态变量方式
public class Singleton {
private static Singleton singleton = new Singleton();
/**
* 私有构造方法
*/
private Singleton() {}
public static Singleton getInstance() {
return singleton;
}
}
1.2 饿汉式-2
静态代码块方式
public class Singleton {
private static Singleton singleton;
private Singleton() {}
static {
singleton = new Singleton();
}
public static Singleton getInstance() {
return singleton;
}
}
1.3 饿汉式-3
枚举方式
public enum Singleton {
SINGLETON
}
1.4 懒汉式-1
线程不安全
public class Singleton {
private static Singleton singleton = null;
private Singleton() {}
public static Singleton getInstance() {
if (singleton == null) {
singleton = new Singleton();
}
return singleton;
}
}
1.5 懒汉式-2
线程安全-1
public class Singleton {
private static Singleton singleton = null;
private Singleton() {}
public static synchronized Singleton getInstance() {
if (singleton == null) {
singleton = new Singleton();
}
return singleton;
}
}
1.6 懒汉式-3
线程安全-2
public class Singleton {
/**
* volatile:禁止指令重排
*/
private static volatile Singleton singleton;
/**
* 构造方法私有
*/
private Singleton() {}
/**
* DCL(Double Check Lock)双重校验锁
*/
public static Singleton getInstance() {
if (singleton == null) {
synchronized (Singleton.class) {
if (singleton == null) {
/**
* 对象初始化过程:
* 1 分配对象内存空间
* 2 初始化对象
* 3 指向刚刚分配的内存空间
* 因为 步骤 2 和 步骤 3 没有数据依赖
* 有可能会出现指令重排
* 2 和 3 步骤对调,会导致对象还没有初始化成功
* 取出来的时候对象为 null
*/
singleton = new Singleton();
}
}
}
return singleton;
}
}
1.7 懒汉式-4
静态内部类方式
public class Singleton {
private Singleton() {}
private static class SingletonHolder {
private static final Singleton SINGLETON = new Singleton();
}
public static Singleton getInstance() {
return SingletonHolder.SINGLETON;
}
}
2、破坏单例模式
2.1 序列化方式
以静态内部类为例
public class Singleton implements Serializable {
private Singleton() {}
private static class SingletonHolder {
private final static Singleton SINGLETON = new Singleton();
}
public static Singleton getInstance() {
return SingletonHolder.SINGLETON;
}
}
测试类:
public class Client {
public static void main(String[] args) throws Exception {
writeObject();
readObject();
readObject();
}
/**
* 从文件中读取对象
*/
public static void readObject() throws Exception {
ObjectInputStream objectInputStream =
new ObjectInputStream(new FileInputStream("D:/桌面/1.txt"));
Singleton singleton = (Singleton) objectInputStream.readObject();
System.out.println(singleton);
objectInputStream.close();
}
/**
* 将对象写入到文件中
*/
public static void writeObject() throws Exception {
Singleton instance = Singleton.getInstance();
ObjectOutputStream objectOutputStream =
new ObjectOutputStream(new FileOutputStream("D:/桌面/1.txt"));
objectOutputStream.writeObject(instance);
objectOutputStream.close();
}
}
运行结果:
2.2 反射方式
以静态内部类为例
public class Singleton implements Serializable {
private Singleton() {}
private static class SingletonHolder {
private final static Singleton SINGLETON = new Singleton();
}
public static Singleton getInstance() {
return SingletonHolder.SINGLETON;
}
}
测试类:
public class Client2 {
public static void main(String[] args) throws Exception {
// 获取 class 对象
Class<Singleton> singletonClass = Singleton.class;
// 获取无参构造方法
Constructor<Singleton> constructor = singletonClass.getDeclaredConstructor();
// 取消访问检查
constructor.setAccessible(true);
// 创建两个对象
Singleton singleton1 = constructor.newInstance();
Singleton singleton2 = constructor.newInstance();
System.out.println(singleton1 == singleton2);
}
}
运行结果:
2.3 Unsafe 方式(没有解决办法)
引入依赖:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.6</version>
</dependency>
代码验证:
Singleton singleton = (Singleton) UnsafeUtils.getUnsafe().allocateInstance(Singleton.class);
运行结果
3、解决单例模式被破坏
3.1 序列化方式
添加 readResolve() 方法
public class Singleton implements Serializable {
private Singleton() {}
private static class SingletonHolder {
private final static Singleton SINGLETON = new Singleton();
}
public static Singleton getInstance() {
return SingletonHolder.SINGLETON;
}
/**
* 进行反序列化时,会自动调用该方法,将该方法的返回值直接返回
*/
public Object readResolve() {
return SingletonHolder.SINGLETON;
}
}
3.2 反射方式
通过标志位
public class Singleton implements Serializable {
/**
* 标志位
*/
private static boolean flag = false;
private Singleton() {
/**
* 加锁是为了线程安全
*/
synchronized (Singleton.class) {
if (flag == true) {
throw new RuntimeException("不要试图利用反射破坏单例");
}
flag = true;
}
}
private static class SingletonHolder {
private final static Singleton SINGLETON = new Singleton();
}
public static Singleton getInstance() {
return SingletonHolder.SINGLETON;
}
}
4、在 JDK 中的体现
4.1 Runtime 类
// 饿汉式
public class Runtime {
private static Runtime currentRuntime = new Runtime();
/**
* 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;
}
/** Don't let anyone else instantiate this class */
private Runtime() {}
}