标题概念
单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。
单例模式基本实现
懒汉模式
这是最基本的单例模式,实现了懒加载,但是多线程不安全,没有添加锁synchronized,严格意义上来说这不算是单例模式。
实现方式
public class Singleton {
private static Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
饿汉式
线程安全,比较常用,但容易产生垃圾,因为一开始就初始化
实现方式
public class Singleton {
private static Singleton instance = new Singleton();
private Singleton() {}
public static Singleton getInstance() {
return instance;
}
}
以上两种基本实现方式都有其缺点,那么我们来改造下吧,别说了 看代码
讲解
public class Singleton {
private static Singleton instance;
private Singleton() {
System.out.println("创建单例模式");
}
public static Singleton getInstance() {
if (instance == null) {
if (instance == null) {
instance = new Singleton();
}
}
return instance;
}
}
public static void main(String[] args) {
for (int i = 0; i < 5; i++) {
new Thread() {
@Override
public void run() {
super.run();
Singleton.getInstance();
}
}.start();
}
}
我们期望的结果应该是
创建单例模式
而实际结果是
创建单例模式
创建单例模式
创建单例模式
创建单例模式
创建单例模式
没错就是这样,不要问为什么,这就是多线程的秒处啦
我们都知道无论是什么语言 java、c、go、dart、.net等最终都会转化成在CUP执行的一条条指令,如果当前进程下多个线程在执行任务,cpu会快速切换线程。例子中有5个线程(A,B,C,D,E)同时开启,线程A执行到判断语句if(instance == null) 时,同时快速切换至B或者C或者D或者E,他们的判断条件都成立(instance此时还为空),再次进行多次切换,(线程A、线程B、线程C、线程D、线程E)都进行赋值操作,所以就创建了5个对象
如何解决呢,请看下面
改造
懒汉式加锁
public class Singleton {
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;
}
}
内部静态类模式
当 Singleton 类加载时,静态内部类 SingletonHolder 没有被加载进内存。只有当调用 getUniqueInstance() 方法从而触发SingletonHolder.INSTANCE 时 SingletonHolder才会被加载,此时初始化 INSTANCE 实例。
这种方式不仅具有延迟初始化的好处,而且由虚拟机提供了对线程安全的支持。
public class Singleton {
private static class Instance {
private static Singleton instance = new Singleton();
}
private Singleton() {
System.out.println("创建单例模式");
}
public static Singleton getInstance() {
return Instance.instance;
}
}
枚举模式
这是单例模式的最佳实践,它实现简单,并且在面对复杂的序列化或者反射×××的时候,能够防止实例化多次。
public enum Singleton {
INSTANCE;
public void fun(){}
}
总结
单例模式推荐使用静态内部类和枚举模式,在Android开发中我个人推荐使用静态内部类模式。
单例模式如何暴力破解和防护呢?