单例模式,确保一个类只有一个实例,它又分为饿单例模式(类加载时实例化一个对象给自己的引用,如果对象很大是对内存一种巨大的浪费)和懒单例模式(调用取得实例的方法如getInstance时才会实例化对象)。而懒单例模式稍稍复杂下,主要是要考虑两点是否Lazy 初始化和多线程安全。双重检查锁定是在输入同步块之前和之后检查惰性初始化对象的状态以确定对象是否被初始化。如果没有对float或int以外的任何可变实例进行额外的同步,它就不能以平台独立的方式可靠地工作。使用双重检查锁定对任何其他类型的基元或可变对象进行延迟初始化会使第二个线程使用未初始化或部分初始化的成员,而第一个线程仍在创建它,并使程序崩溃。
有多种方法可以解决这个问题。最简单的一种方法是根本不使用双重检查锁定,而是同步整个方法。对于早期版本的JVM,出于性能原因,通常建议不要同步整个方法。但在较新的JVM中,同步性能有了很大的改进,所以现在这是一个首选的解决方案。如果您希望避免同时使用synchronized,那么可以使用内部静态类来保存引用。内部静态类保证可以延迟加载。
//饿单例模式
//是否 Lazy 初始化:否
//是否多线程安全:是
public class Singleton {
private static Singleton sc = new Singleton();
private Singleton(){
}
public static Singleton getInstance(){
return sc;
}
}
//懒单例模式
//是否 Lazy 初始化:是
//是否多线程安全:是
public class DoubleCheckedLocking {
private static Resource resource;
public static Resource getInstance() {
if (resource == null) {
synchronized (DoubleCheckedLocking.class) {
if (resource == null)
resource = new Resource();
}
} return resource;
}
static class Resource {
}
}
兼容性解决方案
@ThreadSafe
public class SafeLazyInitialization {
private static Resource resource;
public synchronized static Resource getInstance() {
if (resource == null)
resource = new Resource();
return resource;
}
static class Resource {
}
}
/**
* With inner static holder:
*/
@ThreadSaf
public class ResourceFactory {
private static class ResourceHolder {
// This will be lazily initialised
public static Resource resource = new Resource();
}
public static Resource getResource() {
return ResourceFactory.ResourceHolder.resource;
}
static class Resource {
}
}
/**
* Using "volatile":
*/
class ResourceFactory {
private volatile Resource resource;
public Resource getResource() {
Resource localResource = resource;
if (localResource == null) {
synchronized (this) {
localResource = resource;
if (localResource == null) {
resource = localResource = new Resource();
}
}
}
return localResource;
}
static class Resource {
}
}
see