java中单例模式是一种常见的设计模式,一直以为单例模式很简单。
最近在工作中遇到了问题,才发现当单例遇到多线程很容易会出现多个实例。
网上一查才发现,写法有问题,不支持多线程。
public class Singleton {
private static Singleton instance;
private Singleton (){}
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
需要加线程同步,一种比较简单的写法:
public class Singleton {
private static Singleton instance = null;
private Singleton() { }
public static synchronized Singleton getInstance() {
if(instance == null) {
instance = new Singleton();
}
return instance;
}
}
这样 解决了线程安全问题,但是每个线程调用getInstance都要加锁,我们想要只在第一次调用getInstance时加锁,明显这样会影响多线程的效率。
继续优化:
public class Singleton {
private static Singleton instance = null;
private Singleton() { }
public static Singleton getInstance() {
if(instance == null) {
synchronzied(Singleton.class) {
Singleton temp = instance;
if(temp == null) {
temp = new Singleton();
instance = temp
}
}
}
return instance;
}
}
注意不能写成下面这样:(这样会有 指令重排序问题)
public class Singleton {
private static Singleton instance = null;
private Singleton() { }
public static Singleton getInstance() {
if(instance == null) {
synchronzied(Singleton.class) {
if(instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
虽然可以用
volatile来避免指令重排序问题。但是不推荐这样写。(还是存在漏洞)
public class Singleton {
private static volatile Singleton instance = null;
private Singleton() { }
public static Singleton getInstance() {
if(instance == null) {
synchronzied(Singleton.class) {
if(instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
到最后还是老老实实的采用了双重检查,加线程同步,不用volatile的写法:
public class Singleton {
private static Singleton instance = null;
private Singleton() { }
public static Singleton getInstance() {
if(instance == null) {
synchronzied(Singleton.class) {
Singleton temp = instance;
if(temp == null) {
temp = new Singleton();
instance = temp
}
}
}
return instance;
}
}
如果哪位高手有更好的写法,请多指教。