回复
单例模式线程是否安全?
killads
发布于 2020-9-18 15:41
浏览
0收藏
饿汉式缺点: 可能会浪费内存 线程安全
懒汉式缺点:只有在单线程下才有效 多线程下会破坏单例模式 线程不安全
饿汉是线程安全的,我们在这不讨论他,主角是我们的懒汉式!!
public class LazyMan{
//私有化构造方法
private LazyMan(){
}
//创建一个对象 不赋值
private static LazyMan lazyMan;
//对外提供方法
public static LazyMan getInstance(){
if(lazyMan==null){//(1)
try{
//为了更好的体现 多线程 睡眠使所有线程都进入
Thread.sleep(1000);
}catch(Exception e){
e.printStackTrace();
}
lazyMan=new LazyMan();
}
return lazyMan;
}
public static void main(String[] args){
for(int i=0;i<10;i++){
new Thread(()->{
LazyMan.getInstance();
}).start();
}
}
}
结果==> 会创建10个对象
懒汉式线程不安全的原因:
线程不安全的原因:
假设有两个线程A和B A线程到达(1)处时判断lazyMan对象为null此时cpu的执行权被线程B抢去
但A还没有对lazyMan进行实例化
B读取lazyMan对象的状态仍然是null 线程AB都会进入if中通过new 创建两个不同的对象
解决方案:
线程不安全 就给它加锁
private volatile static LazyMan2 lazyMan;
//解决方案 双重检测锁的懒汉式单例 DCL
public static LazyMan1 getInstance() {
if (lazyMan == null) {
synchronized (LazyMan1.class) {
if (lazyMan == null) {// (1)处
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
lazyMan = new LazyMan1(); // 不是原子性操作
/*
* 1.分配内存空间
* 2.执行构造方法 初始化对象
* 3.把这个对象指向这个空间
* volatile只保证可见性 不保证原子性的,但是可以防止指令重排
* */
}
}
}
return lazyMan;
}
还可以用反射暴力破解
public static void main(String[] args) throws Exception {
//反射
LazyMan2 instance1 = new LazyMan2();
Constructor<LazyMan> declaredConstructor =
LazyMan.class.getDeclaredConstructor(null);
declaredConstructor.setAccessible(true); //无视私有的构造器
LazyMan instance2 = declaredConstructor.newInstance();
System.out.println(instance1);
System.out.println(instance2);
}
都会使得懒汉式的单例被破坏 创建多个对象!
##枚举也是线程安全的 即便使用反射也不能破坏其单例模式!!!
枚举的不能破坏单例的方法这里不提.
有关枚举的单例请移步下一篇博客!
作者:____小明同学i
来源:CSDN
分类
标签
赞
收藏
回复
相关推荐