创建懒汉式单例模式线程安全问题

一、在方法上通过synchronized加锁

[Java]  纯文本查看  复制代码
?
1
2
3
4
5
6
7
8
9
public class SingleteExample {
     private static SingleteExample singleteExample;
[p= 30 , 2 , left]    private SingleteExample() {
     }[/p][p= 30 , 2 , left] public synchronized static SingleteExample getInstance() {[/p][/size][/font][p= 30 , 2 , left][font=微软雅黑][size= 3 ]        if (singleteExample == null ) {
             singleteExample = new SingleteExample();
         }
         return singleteExample;
     }
}

 

这种方法可以保证线程安全,但性能会非常差,特别是在并发情况下,当一个线程执行这个方法的时候,其他线程都会被阻塞。
二 在代码块上通过synchronized加锁

[Java]  纯文本查看  复制代码
?
01
02
03
04
05
06
07
08
09
10
11
12
public class SingleteExample2 {
     private static SingleteExample2 singleteExample;
[p= 30 , 2 , left]    private SingleteExample2() {
     }[/p][/size][/font][p= 30 , 2 , left][font=微软雅黑][size= 3 ]    public  static SingleteExample2 getInstance() {
         if (singleteExample == null ) {
             synchronized (SingleteExample2. class ) {
                 singleteExample = new SingleteExample2();
             }
         }
         return singleteExample;
     }
}

 

这种方法只有在SingleteExample2对象为空时才会创建对象,细化了锁的力度,但在并发情况下,线程A,B同时执行这个方法,同时进行判断,都为空,A线程得到锁,初始化,
B线程等A线程释放锁后,B线程接着进行初始化,A  B两个线程得到的不是同一个对象。

三 双重检查

[Java] 纯文本查看 复制代码
?
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
public class SingleteExample3 {
    private static SingleteExample3 singleteExample;
 
    private SingleteExample3() {
    }
 
    public static SingleteExample3 getInstance() {
        if (singleteExample == null) {
            synchronized (SingleteExample3.class) {
                if (singleteExample == null) {
                    singleteExample = new SingleteExample3();
                }
            }
        }
        return singleteExample;
    }
}

B线程得到锁后初始化前仍会判断SingleteExample3对象是否为空,这时SingleteExample3对象已经初始化了,判断结果为false,B不会再次创建对象。

四 指令重排序
创建一个对象分为三步 1.分配内存空间 2.初始化对象 3.将内存空间的地址赋值给对象的引用。
其中2、3步执行时虚拟机是会重排序的。若A线程执行时JVM将2 3步重排序,那么此时对象的引用指向的内存空间仅仅只是一个地址,
这时候B线程进行第一次为空判断时,发现不为空,会将对象的引用返回。使用volatile关键字禁止JVM重排序。

[Java]  纯文本查看  复制代码
?
01
02
03
04
05
06
07
08
09
10
11
12
13
14
public class SingleteExample4 {
     private static volatile SingleteExample4 singleteExample;[/size]
[p= 30 , 2 , left][size= 3 ]    private SingleteExample4() {
     }[/size][/p][p= 30 , 2 , left][size= 3 ]    public static SingleteExample4 getInstance() {
         if (singleteExample == null ) {
             synchronized (SingleteExample4. class ) {
                 if (singleteExample == null ) {
                     singleteExample = new SingleteExample4();
                 }
             }
         }
         return singleteExample;
     }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值