1、适用场景
系统中只需要单个对象,例如jdk中Runtime;
2、好处
创建多个资源,既浪费内存资源,也增加了创建对象和回收对象的时间。
3、实现方式
3.1 先看下Runtime的实现方式
public class Runtime {
//Runtime类加载的直接创建了Runtime 对象
private static Runtime currentRuntime = new Runtime();
/**
* Returns the runtime object associated with the current Java application.
* Most of the methods of class <code>Runtime</code> are instance
* methods and must be invoked with respect to the current runtime object.
*
* @return the <code>Runtime</code> object associated with the current
* Java application.
*/
public static Runtime getRuntime() {
return currentRuntime;
}
/** Don't let anyone else instantiate this class */
//私有构造函数
private Runtime() {}
实现特点: 类加载过程中创建实现线程安全,基本保证对象按需创建
Runtime 的单例实现方式利用类加载过程的多线程安全来避免多线程环境下的重复创建。基本也实现了对象的按需创建,面试过程中,面试官可能会问没有getRuntime() 就提前创建了对象,会不会造成资源的浪费。关于这点,我想说的是,类加载一般是用户主动加载类或者使用类而类没有加载过,才会加载,一般人也应不会去直接调loadclass吧。所以说Runtime也是在需要时,才创建了对象。
public class Single {
private static volatile Single single;//1、修改对其他线程可见
private Single(){//2、私有的构造函数
}
public static Single getInstance(){
if(single == null){
//3、双空检查,防止重复创建
synchronized (Single.class){
//4
if(single == null){
single = new Single();
}
}
}
return single;
}
}
上述实现的地方有3个关键点:
1、 加volatile字段,多线程环境下,如果一个线程创建了对象并复制给Single对象,如果其他线程不可见,可能在4处依然获得对象为null,进而重复创建对象。
2、私有的构造函数,可以防止客户端在外部直接new一个对象。
3、双空检查,这里没有直接synchronized直接卸载函数方法上,因为加锁是一个重操作,是一个重操作,转而直接判空,会轻量许多。如果多个线程同时到达3处,一个线程进去创建对象后,如果不做第二次判空检查,其他线成进入后也会重复创建对象。
实现的优点:
懒创建: 只在使用的时候,才会创建对象。
多线程: 适用于多线程环境。