Java中单例(Singleton)模式是一种广泛使用的设计模式。单例模式的主要作用是保证在Java程序中,某个类只有一个实例存在。
一、单例模式的特点
- 单例类只能有一个实例。
- 单例类必须自己传教自己的唯一实例
- 单例类必须给所有其他对象提供这一实例
单例模式保证了全局对象的唯一性,比如系统启动读取配置文件就需要单例保证配置的一致性
二、实现单例模式的六种方式
-
饿汉式---静态常量
public class HungrySingleton { // 2.创建类内静态属性为该类对象,并使用final和private进行修饰,避免其能够修改 private static final HungrySingleton HUNGRY_SINGLETON = new HungrySingleton(); // 1.将构造方法私有 private HungrySingleton() { } // 3.将这一个单例使用静态方法返回到调用者手中 public static HungrySingleton getInstance() { return HUNGRY_SINGLETON; } }
- 优点:写法简单,在类装载的时候就完成了实例化,避免了线程同步问题。
- 缺点:如果从始至终未使用过这个实例,会造成内存的浪费。没有懒加载的效果
-
饿汉式---静态代码块
public class StaticCodeBlockSingleton { private static final StaticCodeBlockSingleton STATIC_CODE_BLOCK_SINGLETON; static { STATIC_CODE_BLOCK_SINGLETON = new StaticCodeBlockSingleton(); } private StaticCodeBlockSingleton() { } public static StaticCodeBlockSingleton getInstance() { return STATIC_CODE_BLOCK_SINGLETON; } }
这种方式和上面的方式其实类似,只不过将类实例化的过程放在了静态代码块中,也是在类装载的时候,就执行静态代码块中的代码,初始化类的实例。
-
饿汉式---枚举类
public enum EnumSingleton { //枚举元素本身就是单例 SINGLETON; //添加自己需要的操作 public void singletonOperation(){ } }
- 线程安全,调用效率高,可以天然的防止反射和反序列化调用。
- 不能延时加载,没有懒加载的效果
-
懒汉式---同步方法,线程安全
public class LazySingleton { private static LazySingleton lazySingleton = null; //保证无法通过构造器进行外部实例化 private LazySingleton() { } public static synchronized LazySingleton getInstance() { if (lazySingleton == null) { lazySingleton = new LazySingleton(); } return lazySingleton; } }
- 优点:该模式的特点是类加载时没有生成单例,只有当第一次调用
getlnstance ()
方法时才去开辟内存空间,创建这个单例,线程安全。 - 缺点:高并发的情况下,每次访问
getlnstance ()
方法都要同步,会影响性能,且消耗更多的资源。
- 优点:该模式的特点是类加载时没有生成单例,只有当第一次调用
-
懒汉式---同步代码块,双重检查
public class DoubleCheckLockSingleton { private static DoubleCheckLockSingleton dclSingleton = null; private DoubleCheckLockSingleton() { } public static DoubleCheckLockSingleton getInstance() { //最外层检查是为了效率,后续线程进来发现该类实例已经创建,直接获取 if (dclSingleton == null) { synchronized (DoubleCheckLockSingleton.class) { if (dclSingleton == null) { dclSingleton = new DoubleCheckLockSingleton(); } } } return dclSingleton; } }
- 优点:线程安全;延迟加载;效率较高。
如代码中所示,我们进行了两次
if (dclSingleton == null)
检查,这样,同步代码块中的实例化代码只用执行一次,后面再次访问时,判断if (dclSingleton == null)
,直接return实例化对象。 -
懒汉式---静态内部类
public class StaticInnerClassSingleton { private StaticInnerClassSingleton() { } public static StaticInnerClassSingleton getInstance() { return SingletonClassInstance.INSTANCE; } private static class SingletonClassInstance{ private static final StaticInnerClassSingleton INSTANCE = new StaticInnerClassSingleton(); } }
- 优点:静态内部类方式在
StaticInnerClassSingleton
类被装载时并不会立即实例化,而是在需要实例化时,调用getInstance()
方法,才会装载SingletonClassInstance
静态内部类,从而完成StaticInnerClassSingleton
的实例化。线程安全,调用效率高,可以延时加载。 - 缺点:不能保证反序列化的对象是单例。
- 优点:静态内部类方式在