Consider the case where you have two threads that call getInstance() at the same time. Now imagine T1 executes just past the instance == null check, and then T2 runs. At this point in time the instance is not created or set, so T2 will pass the check and create the instance. Now imagine that execution switches back to T1. Now the singleton is created, but T1 has already done the check! It will proceed to make the object again! Making getInstance() synchronized prevents this problem.
private static final Object lock = new Object();
private static volatile YourObject instance;
public static YourObject getInstance() {
YourObject r = instance;
if (r == null) {
synchronized (lock) { // While we were waiting for the lock, another
r = instance; // thread may have instantiated the object.
if (r == null) {
r = new YourObject();
instance = r;
}
}
}
return r;
}
public class MySingleton {
private static class Loader {
static final MySingleton INSTANCE = new MySingleton();
}
private MySingleton () {}
public static MySingleton getInstance() {
return Loader.INSTANCE;
}
}
public class Singleton {
private static volatile Singleton instance = null;
private Singleton() {
}
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class){
if (instance == null) {
instance = new Singleton();
}
}
}
return instance ;
}
}
在1.5之前,这不是线程安全的,因为 volatile 关键字的实现是不同的。
早期加载 Singleton (甚至在 Java 1.5之前就可以工作)
此实现在加载类时实例化单例并提供线程安全性。
public class Singleton {
private static final Singleton instance = new Singleton();
private Singleton() {
}
public static Singleton getInstance() {
return instance;
}
public void doSomething(){
System.out.println("This is a singleton");
}
}