您的位置:首页 > 其它

关于单例的几点注意事项

2014-12-07 21:54 176 查看
单例在实际的项目中个使用频率比较高,比如环境类,工具类,管理器类,都应该设计成单例,即保证项目运行中该类对象只有一个类对象存在;

第一种写法:

class SingleTon{

private SingleTon() { (1)

}

public static volatile SingleTon sInstance; (2)

public static SingleTon getInstance() {

if (sInstance == null) {

synchronized (SingleTon.class) { (3)

if (sInstance == null) { (4)

sInstance = new SingleTon();

}

}

}

return sInstance;

}

}

这种写法就是定义一个静态的成员变量,只要检查到这个变量为空的话就对这个变量做初始化操作;这里对标注的几个地方做下解释:

(1) 私有化构造函数,这样确保了在类的外部不可能实例化这个类,保证获取类对象的接口只能通过getInstance();

(2) 起关键作用的静态成员变量,值得关注的是volatile修饰符,关于这个修饰符的详细原理就不在这里阐述;需要明白的是public static成员变量的值可以被多线程同时访问,线程在修改这个变量的时候,会先把修改的值缓存在一个属于线程的内存空间,之后再把它写到公共的内存空间里去,也就是说这个变量可能存在多份不一样值的拷贝,这里可能造成的问题就是一个线程初始化了sInstance的值,但是还没写到公共空间,而另一个线程读取了公共空间的值,判断为空,又去初始化一次实例。而volatile的作用恰恰就是禁止这种多分拷贝的存在,使得每个线程读写的都是同样的一块内存,这样就不会存在初始化多个实例的情况;

(3) 只有判断sInstance等于空后才同步代码块,因为同步代码对资源消耗很大,所以synchronized关键字不能滥用;

(4) 当获取同步锁进入后,还要再一次判断是否为空,原因是可能是释放同步锁的线程实例化过对象,此时变量已经不是空;



第二种写法:

class SingalTon{

private SingleTon() {

}

private static class SingleTonHolder {

private static SingleTon sInstance = new SingleTon();

}

public static SingleTon getInstance() {

return SingleTonHolder.sInstance;

}

}

这种写法巧妙的运用了静态内部类,静态内部类只有在调用的时候才会进行类加载,classLoader加载一个类只会加载一次,这样就是借助虚拟机实现了单例的目的,并且不用自己去控制同步;相比上一种简单、明了,所以我很推荐用这种方法,Effective也推荐只用这种方法
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: