单例模式(Singleton Pattern)
单例就是在系统内存中只存在一个对象,用来节约系统资源,减少频繁创建和销毁对象带来的系统开销。
从功能上,单例模式维护系统有且仅有一个实例,并提供全局的访问点,其算是一种职责型模型。
懒汉式单例类,在第一次调用的时候实例化自己,这种单例模式线程不安全,多线程时不能保证类的实例是单例的。代码参如下。
public class Singleton {
// 构造器私有化
private Singleton() {}
private static Singleton instance = null;
public static Singleton getInstance() {//提供全局的访问点
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
该实现方式的优点如下:
★由于实例是在 instance属性方法内部创建的,因此类可以使用附加功能(例如,对子类进行实例化),即使它可能引入不想要的依赖性。
★直到对象要求产生一个实例才执行实例化;这种方法称为“惰性实例化”。惰性实例化避免了在应用程序启动时实例化不必要的实例。
饿汉式单例是指在类初始化时就自行实例化,所以天生线程安全,该实现方式的优点是获取实例不需要每次都进行判断,节约运行时间,代码如下:
//饿汉式单例,在类初始化时已经自行实例化,所以天生线程安全
public class Singleton {
private Singleton() {
}
private static final Singleton singleton = new Singleton();
public static Singleton getInstance() {
return singleton;
}
}
单例在多线程中使用需要考虑线程安全问题,饿汉式单例虽然是线程安全的,但是它在该类加载的时候就会直接实例化一个静态对象出来,当系统中这样的类较多时,会使得启动速度变慢,所以这种方式适合在小系统中。
当系统中这样的类比较多时,可以采用同步方法来处理进行延迟加载,代码如下:
public class Singleton {
private Singleton() {
}
private static Singleton single = null;
// 静态工厂方法,加同步保证线程安全
public static synchronized Singleton getInstance() {
if (single == null) {
single = new Singleton();
}
return single;
}
}
这种方式虽然线程安全,但是同步方法会带来性能问题。解决这个问题可以参考后续几种方式。
代码如下:
public class Singleton {
private static Singleton instance;
private Singleton() {
}
public static Singleton getInstance() {
//先判断一次引用,所有引用不为null的情况都不用进入同步方法了
if (instance == null) {
//对获取实例的方法进行同步,此时引用为null多个请求每次只有一个可以进入同步方法,
synchronized (Singleton.class) {
//只要第一次实例化后,后续引用都不为null,此时再判断一次引用的情况,就可以保证只实例化一次
if (instance == null)
instance = new Singleton();
}
}
return instance;
}
}
代码如下:
//静态内部类实现方式(既线程安全,又避免同步带来的性能影响)
public class Singleton {
private static class LazyHolder{
private static final Singleton INSTANCE = new Singleton();
}
private Singleton() {}
// 静态工厂方法,加同步保证线程安全
public static final Singleton getInstance() {
return LazyHolder.INSTANCE;
}
}
代码如下:
//创建枚举默认就是线程安全的,无需double checked locking。
public enum SingletonEnum {
INSTANCE {
public void singleMethod() {
//some code write here
}
};
protected abstract void singleMethod();
}
单例模式根据单例产生的时机可分为懒汉模式和饿汉模式,其中懒汉模式会延迟加载这样可以避免不必要的单例实例化,节省空间;而饿汉模式在类装载的时候就实例化对象,在获取实例的时可以直接获取,节省时间。
从线程安全方面考虑,饿汉式单例天生线程安全,而懒汉式需要一些处理才行。其中同步方法因为使用同步关键字从而使线程安全,但是会影响性能;双重锁定将实例类作为监视器,并通过两次判断从而保证线程安全,
并且有较好的运行性能。另外枚举方式实现单例代码简单,而且有序列话和线程安全的保证,是比较好的单例实现方式,所以小伙伴们快快get起来吧!