单例模式
针对某一个特别大的资源或者配置文件之类的,我们希望在一个应用中全局只需要一个对象就可以了,不然会造成系统资源的额外浪费,单例模式正是适合这种模式的。
一般常见的创建方式分为懒汉式和饿汉式。
懒汉式
懒汉式,从懒字出发,就是不到使用时,不会去动它,具体使用时调用获取对象方法时才具体创建对象。
这种方式有其有点,在使用的时候才进行初始化,可以节约系统资源,加快应用的启动速度等等,都是有好处的。
/**
* 非线程安全版本
* @author hexin
* @version 1.0 2018/12/17
*/
public class LazySingleton {
private static LazySingleton instance = null;
/**
* 构造函数置为私有,不希望外部调用该方法
*/
private LazySingleton() {}
/**
* 获取单例对象,具体使用时才初始化对象,非线程安全的
*/
public static LazySingleton getInstance() {
if (instance == null)
instance = new LazySingleton();
return instance;
}
}
下面是线程安全版本,使用了双重校验。
/**
* 线程安全版本
* 注意需要jdk1.5以后才行,之前版本的volatile无法保证该特点
* @author hexin
* @version 1.0 2018/12/17
*/
public class MultiThreadSafeLazySingleton {
//使用volatile保证对象不会缓存在cpu cache中。
private volatile static MultiThreadSafeLazySingleton instance = null;
private MultiThreadSafeLazySingleton(){}
/**
* 此单例方法是线程安全的,相对于直接在方法上面使用synchronized关键字,性能好不少,
* 不会限制为单次只有一个线程能够获取对象。
* 是否初始化对象采用了双重校验,保证初始化只有一个对象。
*/
public static MultiThreadSafeLazySingleton getInstance(){
if (instance == null) {
synchronized (MultiThreadSafeLazySingleton.class) {
if (instance == null)
instance = new MultiThreadSafeLazySingleton();
}
}
return instance;
}
}
静态内部类
相对于使用双重校验的那种线程安全实现方式,还有一种更加巧妙的实现线程安全的方式——静态内部类。
利用了java虚拟机的特点,类加载是线程安全的,而且静态内部类相对于其外部类来说是独立的,加载外部类不会立即加载静态内部类,利用这些特点,懒汉式的另一种实现方式如下:
/**
* 使用静态内部类方式实现线程安全的延迟初始化单例对象
* @author hexin
* @version 1.0 2018/12/17
*/
public class StaticInnerLazySingleton {
private StaticInnerLazySingleton(){}
//保存单例的静态内部类
private static class SingletonHolder {
static StaticInnerLazySingleton instance = new StaticInnerLazySingleton();
}
public static StaticInnerLazySingleton getInstance() {
return SingletonHolder.instance;
}
}
饿汉式
正如其名所知,饥饿使得对象是载入该类时即会进行对象的初始化,和懒汉式是对象的。
饿汉式相对于懒汉式,简单,不需要考虑延迟初始化需要的各种处理,但是如果资源比较大的话,占用资源比较多,使应用启动速度减慢等等。
/**
* 饿汉式,立即初始化单例对象,特点是简单,不需要考虑并发造成的问题。
* @author hexin
* @version 1.0 2018/12/17
*/
public class InstantSingleton {
//立即初始化
private final static InstantSingleton instance = new InstantSingleton();
private InstantSingleton(){}
public static InstantSingleton getInstance() {
return instance;
}
}
其他方式
- 枚举类 枚举其实就是很好的单例例子,其每个枚举对象就是一个个的静态实例。