单例模式的线程安全问题

大家都知道单例模式有两种,分别是懒汉式、饿汉式。但是对于饿汉式,由于判断实例为null与创建对象的操作并不是一个原子性操作,故在

多线程环境下,会存在线程安全问题。

普通的懒汉式单例(非线程安全问题):

 1 /**
 2  * Created by ywb 
 3  */
 4 public class Singleton {
 5 
 6     private static  Singleton singleton;
 7     private Singleton() {
 8     }
 9 
10     public static Singleton getInstance() {
11         if(singleton==null) {
12             singleton = new Singleton();
13         }
14         return singleton;
15 
16     }
17 }

第11-13行代码是线程不安全的,为解决问题,可以进行如下改变:

演化版本1:

 1 /**
 2  * Created by ywb 
 3  */
 4 public class Singleton {
 5 
 6     private static  Singleton singleton;
 7     
 8     private Singleton() {
 9     }
10 
11     public synchronized static Singleton getInstance() {
12         if(singleton==null) {
13             singleton = new Singleton();
14         }
15         return singleton;
16     }
17 }

这个版本虽然解决了线程安全问题,但是 synchronized 关键字 却引入了性能问题,可以考虑采用synchronized块缩小同步范围

演化版本2:

 1 /**
 2  * Created by ywb 
 3  */
 4 public class Singleton {
 5 
 6     private static  Singleton singleton;
 7 
 8     private Singleton() {
 9     }
10 
11     public  static Singleton getInstance() {
12         if(singleton==null) {
13             synchronized (Singleton.class) {
14                 singleton = new Singleton();
15             }
16         }
17         return singleton;
18     }
19 }

但是版本2却是存在问题,重新引入了线程安全问题,同步块里可以再次加一个null判断

演化版本3:

 1 package com.tong.qiu;
 2 
 3 /**
 4  * Created by ywb
 5  */
 6 public class Singleton {
 7 
 8     private static volatile Singleton singleton;
 9 
10     private Singleton() {
11     }
12 
13     public  static Singleton getInstance() {
14         if(singleton==null) {
15             synchronized (Singleton.class) {
16                 if(singleton==null) {
17                     singleton = new Singleton();
18                 }
19             }
20         }
21         return singleton;
22     }
23 }

第8行加入了volatile为了保证内存可见性,本版本最终解决了线程安全问题又兼容考虑了性能问题。




When things go wrong,don't go with them.
原文地址:https://www.cnblogs.com/yqy921/p/6275093.html