定义
单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。
建议使用第 3 种饿汉方式。只有在要明确实现 lazy loading 效果时,才会使用静态内部类。如果涉及到反序列化创建对象时,可以尝试使用枚举方式。如果有其他特殊的需求,可以考虑使用双检锁方式
1. 饿汉式
不管用不用我先创建出来,线程安全但占用内存
public class SingleTest {
private static SingleTest singleTest=new SingleTest();
private SingleTest(){};
public static SingleTest getInstance(){
return singleTest;
}
}
2. 懒汉式
用的时候再加载,但线程不安全。
public class SingleTest {
private static SingleTest singleTest;
private SingleTest(){};
public static SingleTest getInstance(){
if (singleTest==null)
singleTest=new SingleTest();
return singleTest;
}
}
3. 懒汉式,线程安全
双重检测并加锁
public class SingleTest {
private static volatile SingleTest singleTest;
private SingleTest(){};
public static SingleTest getInstance(){
// 线程A和线程B判断是否存在
if (singleTest==null){
// 线程A先拿到锁,线程B阻塞
synchronized (SingleTest.class){
//线程A创建对象并赋值,归还锁,线程B进入判断不为null结束。
if (singleTest==null)
// 由于new 不是一个原子性操作,会由指令重排导致一些问题,因此我们在该属性上加上volatile
// 一个对象的创建包括分配空间- 初始化对象- 对象指向空间
// 问题: 线程A创建对象,执行了分配空间,对象指向空间
// 线程B进入拿到对象,返回引用,此时对象其实并没有初始化
singleTest=new SingleTest();
}
}
return singleTest;
}
}
4. 静态内部类实现
SingleTest 类被装载了,singleTest 不一定被初始化。因为 SingleHolder 类没有被主动使用,只有通过显式调用 getInstance 方法时,才会显式装载 SingletHolder 类,从而实例化 singleTest。 线程安全。
public class SingleTest {
private SingleTest(){};
public static SingleTest getInstance(){
return SingleHolder.singleTest;
}
public static final class SingleHolder{
private static final SingleTest singleTest=new SingleTest();
}
}
5. 枚举实现-实现单例模式的最佳方法
之前的方式都可以被反射所破坏,而enum保证了这个
public enum EnumTest {
Instance;
public EnumTest getInstance(){
return EnumTest.Instance;
}
}