单例设计模式所解决的问题就是:保证类的对象在内存中唯一。
1、饿汉
/**
* @说明:饿汉模式
* 解决思路:
* 1.不允许其他程序使用new创建该类对象。(别人new不可控)
* 2.在该类中创建一个本类实例。
* 3.对外提供一个方法让其他程序可以获取该对象。
* 步骤:
* 1.私有化该类的构造函数
* 2.通过new在本类中创建一个本类对象。
* 3.定义一个共有的方法将创建的对象返回。
* @author heyanpeng
*/
public class Single {
private final static Single sigle = new Single();
// 私有化构造函数
private Single () {
}
public static Single getInstance(){
return sigle;
}
}
2、懒汉
/**
* @说明:懒汉模式
* 延迟对象创建,第一次使用的时候创建,节省了内存空间
* 存在的弊端:多线程编程中,使用懒汉式可能会造成类的对象在内存中不唯一
*
* @author heyanpeng
*/
public class Single2 {
private static Single2 single2 = null;
// 私有化构造函数
private Single2(){
}
public static Single2 getInstance(){
if (null == single2) {
single2 = new Single2();
}
return single2;
}
}
总结:
懒汉式在面试的时候经常会被提到,因为知识点比较多,而且还可以和多线程结合起来综合考量。
饿汉式在实际开发中使用的比较多。
3、懒汉式多线程优化
/**
* @说明:懒汉多线程优化
* 在懒汉模式下,if(null == single2) 的判断存在线程安全
*
* @author heyanpeng
*/
public class Single3 {
private static Single3 single3 = null;
// 私有化构造函数
private Single3(){
}
/**
* 方案1: 方法增加synchronized同步
*/
public static synchronized Single3 getInstance(){
if (null == single3) {
single3 = new Single3();
}
return single3;
}
/**
* 方案2: 代码块增加synchronized同步
*/
public static Single3 getInstance2(){
synchronized(Single3.class){
if (null == single3) {
single3 = new Single3();
}
return single3;
}
}
/**
* 方案3: 为空的时候加synchronized同步,再进行为空判断
*/
public static Single3 getInstance3(){
if (null == single3) {
synchronized(Single3.class){
if (null == single3) {
single3 = new Single3();
}
}
}
return single3;
}
}
总结:假设我们现在并没有创建单例对象,即snull,那么我们调用getInstance方法的时候,会进入if块,然后进入同步代码块,此时,别的线程如果想要创建Single实例,就必须获取锁;等当前线程创建完实例对象,释放锁之后,假设正巧有几个线程已经进入了if块中,它们会拿到锁,进入同步代码块,但是由于进行了判空操作,所以不会创建Single实例,而是直接返回已经创建好的Single实例。如果有多个其他线程进入了if块,当它们依次进入同步代码块的时候,同理也不会创建新的Single实例。而没有进入if块的线程,判空操作之后不满足条件,进不了if块,而直接执行了下一条语句return s;其后的线程调用getInstance方法时,只会判断一次snull,不满足条件直接返回Single单例s,这样就大大提高了了执行效率。
第一行代码是第一次判空操作,目的是提高效率;第三行代码是同步代码块的入口,目的是保证线程安全;第五行代码进行第二次判空操作是为了保证单例对象的唯一性。