welcome to xlongwei.com

欢迎大家一起学习、交流、分享


QQ:9167702333 邮箱:admin@xlongwei.com

singleton or synchronized 单例还是同步?


分类 Java   关键字 分享   标签 java   algorithm   发布 hongwei  1433312307607
注意 转载须保留原文链接,译文链接,作者译者等信息。  
singleton单例模式很常用,有时因性能考虑会引入 Lazy init 延迟初始化,又会引入synchronized 同步访问类成员,还有别的方式吗?

最单纯的单例模式,效果相当好,只有在必须要优化的时候才考虑延迟初始化或Holder方式
public class Singleton {
public static final Singleton singleton = new Singleton(); #singleton是final的,所以可以选择public访问
public static Singleton getSingleton() { return singleton; }
private Singleton() {}
}

引入延迟初始化,每次调用都有同步开销
public class Singleton {
private static Singleton singleton; #延迟初始化后就最好是private访问
public static synchronized Singleton getSingleton() { #同步整个方法调用
if(singleton==null) {
singleton = new Singleton();
}
return singleton;
}
private Singleton() {}
}

二次检查方式,这种方法并不能正确的工作,带来问题后难以排查
public class Singleton {
private static Singleton singleton;
public static Singleton getSingleton() {
if(singleton==null) { #只有单例未初始化时才进入同步块
synchronized (Singleton.class) {
if(singleton==null) {
singleton = new Singleton();
}
}
}
return singleton;
}
private Singleton() {}
}

Holder方式,只有当一个类被用到的时候它才被初始化,限制是只能用于静态域
public class Singleton {
private static class SingletonHolder {
static final Singleton singleton = new Singleton();
}
//代码里可以放心的写Singleton.getSingleton().toString(),只有运行时实际获取单例时才会初始化singleton init
public static Singleton getSingleton() {
return SingletonHolder.singleton;
}
private Singleton() {
System.out.println("singleton init");
}
public static void main(String[] args) {
// System.out.println(Singleton.class); #仅访问Singleton.class时不会打印singleton init
System.out.println(getSingleton()); #访问getSingleton()时才会打印singleton init
}
}

单例的序列化,实现Serializable接口,覆盖readResolve方法,构造函数禁止多次调用
public final class Singleton implements Serializable {
private static final long serialVersionUID = -5828224961859053867L;
public static final Singleton singleton = new Singleton();
public static Singleton getSingleton() { return singleton; }
private Singleton() {
if(singleton!=null)
throw new AssertionError();
}

private Object readResolve() throws ObjectStreamException {
return singleton;
}

public static void main(String[] args) throws IOException, ClassNotFoundException {
Singleton singleton = Singleton.getSingleton();

ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(singleton);
byte[] data = baos.toByteArray();

ByteArrayInputStream bais = new ByteArrayInputStream(data);
ObjectInputStream ois = new ObjectInputStream(bais);
Singleton read= (Singleton)ois.readObject();
System.out.println(singleton+(singleton==read?" equals ":" not equals ")+read);
//com.qingbo.front.web.Singleton@794322d1 equals com.qingbo.front.web.Singleton@794322d1 #单例仅有一个实例

new Singleton();
//Exception in thread "main" java.lang.AssertionError
}
}