设计模式-单例模式改进
程序员文章站
2024-01-24 09:22:40
...
对原单例模式改进
原单例模式存在缺陷
原单例模式的实现在多线程场景下,在线程1判断实例为空之后实例化赋值之前,另外一个线程开始判断实例为空,这时两个线程的判断结果都是实例对象为空,从而都创建实例,导致两个线程中获取的实例不是同一个实例
改进思路1
既然多线程获取实例时,可能会存在问题,那么只需要对获取实例的方法加锁,这样就不会出现以上问题
改进实现1
package com.qsy.singleton.advanced;
/**
* <pre>更高级的单例模式,主要考虑多线程情况下</pre>
* @author yangsx
* @date 2019年9月18日
*/
public class SingletonBean {
private static SingletonBean uniqueInstance = null;
/**
* <pre>构造函数私有化</pre>
* @author yangsx
* @date 2019年9月18日
*/
private SingletonBean() {
}
/**
* <pre>共有静态方法对外提供实例</pre>
* 获取实例时,多线程可能会出现返回多个实例的问题,主要考虑在new之前,另外一个线程也在判断空
* 初次创建实例时,多个线程竞争锁就会消耗过多资源
* @author yangsx
* @date 2019年9月18日
* @return
*/
public synchronized static SingletonBean getInstace() {
if (uniqueInstance == null) {
uniqueInstance = new SingletonBean();
}
return uniqueInstance;
}
}
改进实现 1存在的缺陷
直接对静态方法加锁,会导致每一次获取实例时都要获取锁资源,在频繁的调用下,每次调用都可能等待占用资源。
分析根本原因是因为多线程下,判断null为空可能会同时执行,只要让实例变量永远不为空,这样就永远能够返回单一实例且不存在冲突问题
改进实现2
package com.qsy.singleton.advanced;
/**
* <pre>更高级的单例模式,主要考虑多线程情况下</pre>
* <pre>饥汉模式</pre>
* @author yangsx
* @date 2019年9月18日
*/
public class SingletonBean2 {
/**
* 体现饥汉模式
* 不用的时候存在内存浪费
*/
private static SingletonBean2 uniqueInstance = new SingletonBean2();
/**
* <pre>构造函数私有化</pre>
* @author yangsx
* @date 2019年9月18日
*/
private SingletonBean2() {
}
/**
* <pre>公有静态方法对外提供实例</pre>
* @author yangsx
* @date 2019年9月18日
* @return
*/
public static SingletonBean2 getInstace() {
// if (uniqueInstance == null) {
// uniqueInstance = new SingletonBean2();
// }
return uniqueInstance;
}
}
改进实现2存在的缺陷
正如代码中所说,当不需要使用当前实例时,就会存在内存浪费,所以有如下改进
改进实现3
package com.qsy.singleton.advanced;
/**
* <pre>双重检查加锁法实现单例模式</pre>
* @author yangsx
* @date 2019年9月18日
*/
public class SingletonBean3 {
/**
* volatile多线程可见
*/
private volatile static SingletonBean3 uniqueInstance = null;
/**
* <pre>构造函数私有化</pre>
* @author yangsx
* @date 2019年9月18日
*/
private SingletonBean3() {
}
/**
* <pre>公有静态方法对外提供实例
* 双重校验加锁
* </pre>
* @author yangsx
* @date 2019年9月18日
* @return
*/
public static SingletonBean3 getInstace() {
if (uniqueInstance == null) {
// 方法不会加锁,只要创建过一次,就不会再存在锁竞争
synchronized (SingletonBean3.class) {
// 确保获取锁之后uniqueInstance没有被创建才需要创建实例
if (uniqueInstance == null) {
uniqueInstance = new SingletonBean3();
}
}
}
return uniqueInstance;
}
}
上一篇: MySQL 设置全局变量
下一篇: 内部类、设计模式