文章目录
一、双重枷锁的懒汉模式
public class Sun {
/**
* 构造私有化
*/
private Sun() {
System.err.println("Sun 对象初始化..........");
}
private static Sun sun;
public static Sun getInSun() {
if (sun == null) {
synchronized(Sun.class){
if (sun==null) {
sun = new Sun();
return sun;
}
}
}
return sun;
}
}
经过双重验证+同步代码块多线程创建对象测试
for (int i = 0; i <20000; i++) {
new Thread(){
public void run() {
Sun.getInSun();
};
}.start();
}
创建20000个线程同时获取对象,通过log看,对象确实只创建了一个
Sun 对象初始化..........
但是这样就安全了么?虽然构造方法私有化了,但是我们可以通过反射的方法去创建对象,这种情况下我们的对象还能保证唯一性么?通过测试看下结果
try {
Class sun = Sun.class;
Constructor constructor = sun.getDeclaredConstructor();
constructor.setAccessible(true);
Sun sun2 = (Sun) constructor.newInstance();
System.out.println(sun2==Sun.getInSun());
} catch (Exception e) {
// TODO Auto-generated catch block
System.out.println("已经初始化了不能再初始化了");
}
通过反射的方式创建对象,再通过正常获取对象的方式获取对象,看两个对象是一个?通过测试发现,对象被创建了2次,且两个对象不是同一个对象。那么这中情况怎么处理呢?暂时没有好的方法去处理,因为对象是每次调用的时候才创建,所以看看其他方式是否能解决
Sun 对象初始化..........
Sun 对象初始化..........
false
二、饿汉模式
public class Moon {
private Moon(){
System.err.println("对象被创建了。。。。。。。。。。");
}
private static Moon moon=new Moon();
public static Moon getMoon(){
return moon;
}
}
和之前一样先测试下,多线程下对象是不是唯一
for (int i = 0; i <20000; i++) {
new Thread(){
public void run() {
Moon.getMoon();
};
}.start();
}
很显然多线程下,对象唯一性没毛病
对象被创建了。。。。。。。。。。
接下来我们依旧使用反射的方法去获取对象和正常情况下获取对象看是否是同一个对象
try {
Class sun = Moon.class;
Constructor constructor = sun.getDeclaredConstructor();
constructor.setAccessible(true);
Moon sun2 = (Moon) constructor.newInstance();
System.out.println(sun2==Moon.getMoon());
} catch (Exception e) {
// TODO Auto-generated catch block
System.out.println("已经初始化了不能再初始化了");
}
对象被创建了。。。。。。。。。。
对象被创建了。。。。。。。。。。
false
很显然依然是创建了多个对象,两个对象也不相同,也不能保证对象的唯一性,那么有什么方法能够避免这种情况的发生么?饿汉模式下的单例模式,对象是再类加载的时候去创建的对象,当再去反射获取对象的时候,这个对象作为类的静态资源已经存在,可能再构造方法中做处理,判断对象!=null的时候直接抛出异常,从而阻止反射创建对象。测试一把
public class Moon {
private Moon(){
if (moon!=null) {
throw new NullPointerException();
}
System.err.println("对象被创建了。。。。。。。。。。");
}
private static Moon moon=new Moon();
public static Moon getMoon(){
return moon;
}
}
====================================================================================
通过log可以看出来确实创建一个对象,当通过反射去创建对象直接抛出异常,这个异常可以自己定义,我这为了方便就先返回一个空指针异常。
对象被创建了。。。。。。。。。。
已经初始化了不能再初始化了