单例设计模式
需求:希望某一个类只有一个唯一的实例
实现例子:
步骤
- 将构造函数私有化
- 在类的内部创建实例
- 提供获取唯一实例的方法
//设计一个单例类
恶汉模式:在类加载的时候创建了唯一对象,对系统的开销相对较大,可能会产生影响软件启动的延时问题
class MySingleton{
// instance指向唯一的实例,类加载的时候执行,只执行一次
private static MySingleton instance=new MySingleton();
// 私有化构造方法
private MySingleton(){ }
// 必须对外提供一个可以访问唯一实例的方法,并返回该唯一实例
public static MySingleton getInstance(){
return instance;
}
}
设计一个单例类
懒汉模式:就是在第一次调用getInstance的时候创建唯一的实例。
class MySingleton{
private static MySingleton instance;
private MySingleton(){}
public static MySingleton getInstance(){
if (instance==null){
//stop
instance=new MySingleton();
}
return instance; }}
如果这样设计,有多个线程的话,线程A看到instance为null,因为某种原因停止(如sleep()),线程B进去。这样导致生成两个实例。
方法1:在getInsatnce()前加sychronized关键字。
方法2:
直接加上对象锁。
缺点:不管是否已经生成一个唯一的实例,都要获得对象锁。
synchronized (MySingleton02.class) {
if (instance == null) {
instance = new MySingleton02(); } }
方法3:
没有生成唯一的实例时,才需要获取对象锁
优点:将锁的范围缩小,提高性能
缺陷:线程A和线程B同时调用getInstance()方法,得出的结果都是null。线程A虽然先得到CPU的控制权创建对象,线程B之后也得到了CPU的控制权创建新的对象,所以返回了不只一个实例。
解决方法:用双重检测机制(DCL),再次判断是否为空
if (instance == null) {
synchronized (MySingleton02.class) {
instance = new MySingleton02();}}
方法4:
双重检测机制(DCL),且加上volatile关键字,此关键字有内存屏障的功能。
class MySingleton{
private static volatile MySingleton02 instance;
private MySingleton(){}
private static MySingleton02 getInstance(){
if (instance == null) {
synchronized (MySingleton02.class) {
if(instance==null){
instance = new MySingleton02();}
}
}
return instance;
}
}