单例模式是一个比较简单的设置模式,在我们编码的过程中,有一些类会经常使用到,但是只需要一个实例就可以实现,如果大量的创建实例,可能会导致许多问题,如资源的大量使用、程序异常等。
这时候就轮到单例模式展现他的力量了。
单例模式确保了一个类只有一个实例,并提供了一个全局的访问点,下面我们看一个最简单的单例模式。
public class Singleton { private static Singleton unqueInstance; private Singleton() { } public static Singleton getInstance() { if (unqueInstance == null) { unqueInstance = new Singleton(); } return unqueInstance; } }
将对象的构建器属性设置为私有变量,这样他就不会被其他的外部类调用,导致实例化多个对象,同时定一个静态公共方法,用来获取实例,只有在第一次使用的时候才会对其进行创建。
但是这种单例模式有一个问题,就是在多线程的时候,如果同时两个线程调用getInstance()方法,就会导致程序出现异常,这个时候我们可以稍微简单的改下这个例子,不使用延迟实例,在静态初始化器中创建单例。
public class Singleton { private static Singleton unqueInstance = new Singleton(); private Singleton() { } public static Singleton getInstance() { return unqueInstance; } }
这样虽然解决了,线程安全的问题,但是如果这个类在创建和运行时负担比较严重,在程序启动时进行创建,就会使程序启动的缓慢,这时候我们可以用加锁的形式进行单例模式的改造。
public class Singleton { private volatile static Singleton unqueInstance; private Singleton() { } public static Singleton getInstance() { if (unqueInstance == null) { synchronized (Singleton.class) { if (unqueInstance == null) { unqueInstance = new Singleton(); } } } return unqueInstance; } }
这样改造下,就可以避免因为多线程导致单例出现问题。
还有一种方式,利用内部静态类的方式,也可以解决多线程的问题。
public class Singleton { private static class SingletonHolder { private static Singleton singleton = new Singleton(); } private Singleton() { } public static Singleton getInstance() { return SingletonHolder.singleton; } }
在java中还可以利用枚举实现单例模式
public enum SingletonEnum { INSTANCE; public SingletonEnum getInstance() { return INSTANCE; } }
使用枚举创建单例模式有很多好处
1. 枚举可解决线程安全问题,比起前面的双重锁校验,代码要精简很多。
2. 传统的单例模式,如果实现了序列化的接口,就不能够再保持单例了,但是枚举的序列化做了特殊处理,可以解决这些问题。
单例模式是一种很常用的设计模式,在程序中,涉及到线程池、缓存、对话框、注册表对象、日志对象等,这些只能有一个实例的对象,就可以使用单例模式。