单例模式
单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。 这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。(摘自菜鸟教程)
- 类图:
实现方式1
/*
* 多线程安全:JVM保证(类只加载一次,instance 初始化一次)
* 恶汉式
* */
public class SingleObject {
private static final SingleObject instance = new SingleObject();
private SingleObject(){};
public static SingleObject getInstance(){
return instance;
}
}
实现方式2
/*
* 多线程安全:synchronized保证, 效率低
* 懒汉式
* */
public class SingleObject2 {
private static SingleObject2 instance ;
private SingleObject2(){};
public synchronized static SingleObject2 getInstance(){
if(instance==null){
instance=new SingleObject2();
}
return instance;
}
}
实现方式3
/*
* 多线程安全:synchronized代码块保证, 锁的粒度小,效率高
* 懒汉式
* */
public class SingleObject3 {
private static volatile SingleObject3 instance ;
private SingleObject3(){};
public static SingleObject3 getInstance() {
if(instance==null) { // 外层判断,用于提高效率
synchronized (SingleObject3.class) {
if (instance == null) { // 内层判断用于,进一步的保证多线程安全
instance = new SingleObject3();
}
}
}
return instance;
}
}
实现方式4
/*
* 多线程安全:JVM保证(类加载,静态内部类)
* 懒汉式
* */
public class SingleObject4 {
private SingleObject4(){};
private static class instanceHolder {
private final static SingleObject4 instance = new SingleObject4();
}
public static SingleObject4 getInstance() {
return instanceHolder.instance;
}
}
实现方式5
/*
* 多线程安全,防止反序列化(没有构造方法,更加严谨)
* 枚举单例
* */
public enum SingleObject5 {
INSTANCE;
public static void main(String[] args) {
for (int i = 0; i < 100; i++) {
new Thread(()->{
System.out.println(SingleObject5.INSTANCE.hashCode());
}).start();
}
}
}
总结
- 个人推荐 方式1,和方式4(静态内部类)。
- 对于 枚举单例(严谨),根据具体情况选择
- 对于普通的单例,可以通过暴力反射来获取实例(打破单例)
public class Test {
public static void main(String[] args) throws Exception {
SingleObject4 instance = SingleObject4.getInstance();
/*单例接口获取 实例*/
System.out.println(instance.hashCode());
/*暴力反射获取 实例*/
Class<? extends SingleObject4> clazz = instance.getClass();
Constructor<? extends SingleObject4> constructor = clazz.getDeclaredConstructor();
constructor.setAccessible(true);
System.out.println(constructor.newInstance().hashCode());
}
}