单例模式,算是这些模式当中最简单的一个模式了,面试的时候如果问设计模式,貌似很多都会问到这个。
单例模式定义:确保一个类只有一个实例,并提供一个全局访问点。OK,由于此模式较简单,这里就不举什么
生活中的例子了,直接看代码:
/**
* 饥汉式,立即加载
*/
public class Singleton {
private static Singleton uniqueInstance = new Singleton();
private Singleton() {}
public static Singleton getInstance() {
return uniqueInstance;
}
}
/**
* 饱汉式,延迟加载,双重锁机制
*/
public class Singleton {
private volatile static Singleton uniqueInstance;
private Singleton() {}
public static Singleton getInstance() {
if (uniqueInstance == null) {
synchronized (Singleton.class) {
if (uniqueInstance == null) {
uniqueInstance = new Singleton();
}
}
}
return uniqueInstance;
}
}
/**
* 不用加锁实现饱汉式
*/
public class SingletonKerriganF {
private static class SingletonHolder {
/**
* 单例对象实例
*/
static final SingletonKerriganF INSTANCE = new SingletonKerriganF();
}
public static SingletonKerriganF getInstance() {
return SingletonHolder.INSTANCE;
}
}
对于延迟加载方式的单例模式,只有在第一次用到的时候,再会实例化此类,不过此方式只适合java1.5及以上版本才适合,原因跟JVM有关,许多JVM对于volatile
关键字的实现会导致双重检查加锁失效,在1.5以后调整了JMM(Java Memory Model),具体化了volatile关键字
对于此处的volatile的用法就跟线程有关了,这里简单介绍下锁的特性:
锁提供了两个特性:1.互斥,2.可见性。互斥就是一次只有一个线程持有改锁,可以使用共享数据。可见性复杂点:必须确保释放锁之前对于共享数据的修改对于随后
获得该锁的另一个线程是可见的。
volatile变量具有sychronized的可见性,就是说线程能够自动发现volatile变量的最新值。
此处的解释就是:当两个线程同时运行完if (uniqueInstance == null) 后,只有一个线程得到锁,实例化uniqueInstance,如果没有volatile当第二个线程拿到
uniqueInstance,可能还没有实例化结束,结果就杯具了,不过只要加上volatile让线程只操作主存数据就OK(具体以后可以研究下JMM)
OK,单例就到此结束,代码其实非常简单,不过用处挺大,比如线程池等都需要用到单例