这样可能会出现线程不同的方法,所以必须对getSingleton方法进行同步。
public class Singleton { private static Singleton singleton;//私有静态变量
private Singleton(){};//私有构造方法
//全局静态访问入口
public static Singleton getSingleton(){
if(singleton==null){
singleton=new Singleton();
}
return singleton;
}
}
public class Singleton { private static Singleton singleton;//私有静态变量
private Singleton(){};//私有构造方法
//全局静态访问入口
public static synchronized Singleton getSingleton(){
if(singleton==null){
singleton=new Singleton();
}
return singleton;
}
}
这样子线程就安全了,但是消耗了不必要的同步资源,不推荐这样使用。
public class Singleton {
private static Singleton singleton=new Singleton();//私有静态变量
private Singleton(){};//私有构造方法
//全局访问入口
public Singleton getSingleton(){
return singleton;
}
}
避免线程安全问题,在声明私有静态变量时,就已经实例化了类,不用考虑线程同步问题。
public class Singleton { private static Singleton singleton;//私有静态内部变量
private Singleton(){};//私有构造方法
//全局访问入口
public static synchronized Singleton getSingleton(){
if(singleton==null){
synchronized (Singleton.class){
if(singleton==null){
singleton=new Singleton();
}
}
}
return singleton;
}
}
通过两个判断,第一层是避免不必要的同步,第二层判断是否为null。 可能会出现DCL模式失效的情况。 DCL模式失效: singleton=new Singleton();这句话执行的时候,会进行下列三个过程:
由于JMM(Java Memory Model)的规定,可能会出现1-2-3和1-3-2两种情况。 所以,就会出现线程A进行到1-3时,就被线程B取走,然后就出现了错误。这个时候DCL模式就失效了。 Sun官方注意到了这种问题,于是就在JDK1.5之后,具体化了volatile关键字,这时候只用调整一行代码即可。
private volatile static Singleton singleton;
public class Singleton { private Singleton(){}
public static Singleton getSingleton(){
return SingletonHolder.singleton;
}
private static class SingletonHolder{
private final static Singleton singleton=new Singleton();
}
}
第一次加载Singleton类不会加载SingletonHolder类,但是调用getSingleton时,才会加载SingletonHolder,才会初始化singleton。即确保了线程安全,又保证了单例对象的唯一性,延迟了单例的实例化。这是最推荐的方式。
public enum Singleton{
singleton;
public void hello(){
System.out.print("hello");
}
}
这样很简单,线程时安全的,并且避免了序列化和反射攻击。 除了枚举模式,其他模式在实现了Serializable接口后,反序列化时单例会被破坏。所以要重写readResolve()方法。
private Object readResolve() throws ObjectStreamException {
return INSTANCE;
}
public class SingletonManger{
private static Map<String,Object> objectMap=new HashMap<String,Object>();
private SingletonManger(){}
public static void registerService(String key,Object singleton){
if(!objectMap.containsKey(key)){
objectMap.put(key,singleton);
}
}
public static Object getObjectService(String key){
return objectMap.get(key);
}
}
这样可以将多个单例对象注入到HashMap中,进行统一管理,更加方便快捷。