单例模式的线程安全问题
大家都知道单例模式有两种,分别是懒汉式、饿汉式。但是对于饿汉式,由于判断实例为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.