关于单例的几点注意事项
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也推荐只用这种方法
第一种写法:
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也推荐只用这种方法
相关文章推荐
- 关于C# 打包的几点注意事项
- 关于笔记本使用的几点注意事项
- 关于使用READ TABLE语句的几点注意事项...(原文来源于网络)
- 关于网格比较工具metro使用的几点注意事项
- 关于使用ZXing开发几点注意事项
- Android中关于线程使用的几点注意事项
- 关于喝牛奶的几点注意事项 - 生活至上,美容至尚!
- 关于C++语句的几点注意事项
- Android中关于线程使用的几点注意事项
- 关于Aspose.NET使用的几点注意事项
- 关于笔记本使用的几点注意事项
- 关于使用READ TABLE语句的几点注意事项
- Android中关于线程使用的几点注意事项
- 关于MongoDB的几点注意事项
- ABAP 筑基宝典(5) -- 关于使用READ TABLE语句的几点注意事项
- 关于使用READ TABLE语句的几点注意事项...(原文来源于网络)
- ASP.NET学习笔记[2] - 关于使用Master.Page的几点注意事项
- 关于MongoDB的几点注意事项
- 关于使用READ TABLE语句的几点注意事项
- 关于使用READ TABLE语句的几点注意事项