单例:保证一个类仅有一个实例,并提供一个访问它的全局访问点。
单例模式是一种常用的软件设计模式之一,其目的是保证整个应用中只存在类的唯一个实例。
比如我们在系统启动时,需要加载一些公共的配置信息,对整个应用程序的整个生命周期中都可见且唯一,这时需要设计成单例模式。如:spring容器,session工厂,缓存,数据库连接池等等。
保证实例的唯一:
- 防止外部初始化
- 由类本身进行实例化
- 保证实例化一次
- 对外提供获取实例的方法
- 线程安全
饿汉式单例模式
线程安全,调用效率高,但是不能延时加载
直接创建单例对象,使用的时候直接返回即可。缺点是单例在未使用的时候就已经初始化完成,如果程序一直没有使用,单例对象还是会创建,从而造成不必要的资源浪费。
1 2 3 4 5 6 7 8 9
| public class TestA { private static TestA t1 = new TestA; private TestA() {}
public static TestA getInfo() { return t1; } }
|
懒汉式单例模式
线程安全,调用效率不高,但是可以延时加载
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| public class TestB { private static TestB t2;
private TestB() {}
public static synchronized TestB getInfo() { if (testB == null) { TestB = new TestB(); } return testB; } }
|
双重锁判断机制(DCL)
即Double CheckLock实现单例模式(由于JVM底层模型原因,偶尔会出现问题,不建议使用)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| public class TestC { private static TestC t3; private TestC() {}
public static TestC getInfo() { if (TestC == null) { synchronized (TestC.class) { if (TestC == null) { TestC = new TestC(); } } }
return t3; } }
|
静态内部类实现单例模式
线程安全,调用效率高,可以延迟加载
1 2 3 4 5 6 7 8 9 10 11 12 13
| public class TestD {
private static class GetInfoClass { private static final TestD t4 = new TestD(); }
private TestD() {}
public static TestA getInfo() { return GetInfoClass.t4; } }
|
枚举类实现单例模式
线程安全,调用效率高,不能延时加载,可以天然防止反射和反序列化调用)
1 2 3 4 5 6 7 8 9
| public class TestE { INSTANCE;
public void getInfoOperation() { } }
|