定义
确保某个类只有一个实例,并且自行实例化,向整个程序提供实例对象
使用场景
创建某个对象很耗费资源或者某一种类型的对象只应该有一个的时候,比如线程池(threadpool)、缓存(cache)、对话框、日志对象、处理偏好设置、打印机、显卡等对象,只应该有一个,如果制造出了多个对象,那么就有可能造成程序的异常行为,资源使用过量或者结果不一致等问题。
单例设计模式的实现
1、私有化构造方法
2、通过一个静态的方法返回单例类对象
3、确保单例类对象有且只有一个,特别是在多线成的情况下
4、确保单例类对象不会再反序列化的时候不会重新构建对象
通过私有化构造方法,单例类暴露一个静态的公共方法,通过调用这个方法得到单例类的唯一对象,在获取这个对象的过程中确保线程的安全性。
饿汉单例类
public static Singleton{
private static final Singleton uniqueInstance=new Singleton();
private Singleton(){
}
//提供静态的公共方法,让外部获取到该对象
public static Singleton getInstance(){
return uniqueInstance;
}
}
懒汉模式
public static class Singleton2 {
private static Singleton2 instance = null;
private Singleton2() {
}
public static Singleton2 getInstance() {
if (instance == null) {
instance = new Singleton2();
}
return instance;
}
}
tips:可以这样来记忆懒汉和饿汉,饿汉式就比如是一个很饥饿的人,上来就先创建对象。而懒汉则是等到需要的时候在创建对象,什么时候不需要就不去创建。
懒汉式的优点是在使用的时候才会初始化对象,在一定的程度上节约了资源,但是第一次加载的时候需要及时序列化,反应慢,而且每次调用getInstance()方法的时候都需要同步,造成了很大的开销,因此一般不用这个方法。
处理多线程
通过添加synchronized关键字到getInstance()方法中,是每一个线程进入这个方法之前,要先等候别的线程离开这个方法,然后在执行,这样就不会有两个线程同时进入这个方法。
public class Singleton1 {
private static Singleton1 uniqueInstance;
private Singleton1() {
}
public static synchronized Singleton1 getInstace() {
if (uniqueInstance == null) {//uniqueInstance对象为null的时候才去创建
uniqueInstance = new Singleton1();
}
return uniqueInstance;
}
}
双重检查加锁
利用双重检查加锁(DCL),首先检查时候已经创建实例,如果尚未创建,才进行同步,这样第一次会同步,不会每次都同步,减少了消耗,正是我们想要的。
public class Singleton {
private static volatile Singleton uniqueInstance;
private Singleton() {
}
/**
* 这个方法可以大大减少getInstance()的时间耗费
*
* volatile关键字确保了uniqueInstance变量被初始化的时候多个线程可以正确的处理uniqueInstance变量
* 使用volatile修饰以后,在一个线程中修改了某个变量的值,在其他线程中立即可见
*/
public static Singleton getInstance() {
if (uniqueInstance == null) {//检查实例,如果不存在,进入同步区域
synchronized (Singleton.class) {
if (uniqueInstance == null) {//进入区块以后在检查一次,如果还是为null,那么创建实例
uniqueInstance = new Singleton();
}
}
}
return uniqueInstance;
}
}
这个方法对实例进行了两次判空,第一次是为了避免不必要的同步,第二次是为了避免为null的情况下才去创建实例。