- 饿汉模式
即先创建实例等着被用,当类加载得时候就完成了创建对象,当外部使用此类得实例的时候只能通过getInstance()方法,如果没有用到此类的实例,那就浪费了空间资源。
public class MyObject {
private static MyObject myObject = new MyObject();
private MyObject(){
}
public static MyObject getInstance(){
return myObject;
}
}
- 懒汉模式
即用的时候才创建实例,单例模式:懒汉式在基础上加入并发控制,保证在多线程得情况下,对外存在一个对象
- 构造器私有化,避免外部new构造器
- 提供私有的静态属性,存储对象地址
- 提供静态方法,获取属性
DoubleChecking方式,如果类的成员变量没有实例,则创建实例,存在实例直接返回。多线程下有一个线程率先创建实例,其他线程不会再创建实例,通过if语句检测直接return,保证对外存在一个对象。返回之前再变量加上volatile,(此处可能出现指令重排,创建对象过程中1. 先开劈空间2. 初始化对象信息3. 返回对象的引用地址,在完成初始化之前就进行第三步,返回地址,就会造成对象信息为空。为避免加上volatile)防止指令重排。
public class DoubleCheckedLocking {
//2. 提供私有的静态属性,存储对象地址
private static volatile DoubleCheckedLocking Instance;//实例//避免重排//同步更新
// 1. 构造器私有化,避免外部new构造器
private DoubleCheckedLocking (){
}
//3. 提供静态方法,获取属性
public static DoubleCheckedLocking getInstance() {
if(null!=Instance){//如果已经存在对象,避免不必要的同步
return Instance;
}
synchronized (DoubleCheckedLocking.class) {
if (Instance == null) {
Instance = new DoubleCheckedLocking();
}
}
return Instance;//此处可能出现指令重排,创建对象过程中1. 先开劈空间2. 初始化对象信息3. 返回对象的引用地址,
// 在完成初始化之前就进行第三步,返回地址,就会造成对象信息为空。为避免加上volatile
}
public static void main(String[] args) {
Thread t1= new Thread(()->{
System.out.println(DoubleCheckedLocking.getInstance());
});
t1.start();
System.out.println(DoubleCheckedLocking.getInstance());
}
}
运行结果:
ThreadAdTheme.DoubleCheckedLocking@12edcd21
ThreadAdTheme.DoubleCheckedLocking@12edcd21
结果显示,new 对象的地址相同。创建了一个对象