介绍
即在整个应用程序运行过程中, 只应该存在一个实例的类, 则适合使用单例模式.
解决问题: 避免一个全局使用的类被频繁的创建与销毁
例子
单例模式的几种不同的使用方式
饿汉模式
即在应用程序初始化时,就载入单例服务,不考虑服务是否会真的被使用.
这个模式是线程安全的, 类的静态属性的初始化由 JVM 来保证原子性和可见性
public class Singleton {
private Singleton(){};
private static final Service service = new Service();
public static Service getInstance() {
return service;
}
}
懒汉模式
即 在第一次调用时才初始化所需要的单例类, 可避免 使用饿汉模式,导致服务并未被使用,却被提前加载耗费资源的情况.
懒汉模式的实现有几种, 下面我按照推崇程度的写法依次说明.
使用 静态内部类
实现懒加载
这种方法,实现简单, 无需额外的加锁等操作, 原子性和可见性由 JVM 来保证.
public class Singleton {
private Singleton(){};
public static Service getInstance() {
return SingletonHolder.INSTANCE;
}
private static class SingletonHolder {
private static final Service INSTANCE = new Service();
}
}
使用 自己加锁的方式 实现懒加载
这种方式,也能保证线程安全性,实现也比较简单,但是由于每一次获取 Service 时都会进行加解锁过程,从而导致产生大量无用的加解锁操作,降低了程序性能.
public class Singleton {
private Singleton(){};
private static Service service;
public static synchronized Service getInstance() {
if (null == service) {
service = new Service();
}
return service;
}
}
使用 DCL (Double Check Lock) 实现懒加载
注意这里需要将 单例服务 设置为 volatile 从而阻止指令重排序 ( 在java 1.4 及 之前的版本也是不起作用的 ). DCL这种方式就避免了上面的大量无用加解锁操作. 关于 DCL的说明(传送门)
public class Singleton {
private Singleton(){};
private static volatile Service service;
public static Service getInstance() {
if (null == service) {
synchronized (Singleton.class) {
if (null == service) {
service = new Service();
}
}
}
return service;
}
}