java单例模式的6种写法

第一种(懒汉,线程不安全)
public class Singleton
{
    private static Singleton instance;
    private Singleton()
    {
    }

    public static Singleton getInstance()
    {
        if(null == instance)
        {
            instance = new Singleton();
        }
        return intance;
    }
}
这种写法lazy loading很明显,但致命的是在多线程不能正常工作。


第二种(懒汉,线程安全)
public class Singleton
{
    private static Singleton instance;
    private Singleton()
    {
    }

    public static synchronized Singleton getInstance()
    {
        if(null == instance)
        {
            instance = new Singleton();
        }
        return intance;
    }
}
这种写法能够在多线程中很好的工作,而且看起来它齐备很好的lazy loading,但是效率很低


第三种(饿汉)
public class Singleton
{
    private static Singleton instance = new Singleton();
    private Singleton()
    {
    }

    public static Singleton getInstance()
    {
        return intance;
    }
}
这种方式基于classloader机制避免了多线程的同步问题,不过instance在类装载时就实例化,没有达到lazy loading的效果。


第四种(静态内部类)
public class Singleton
{
    private Singleton()
    {
    }

    public static Singleton getInstance()
    {
        return SingletonHolder.INSTANCE;
    }

    priate static class SingletonHolder
    {
        private static final Singleton INSTANCE = new Singleton();
    }
}
这种方式同样利用classloader的机制来保证初始化instance是线程安全的,并且是lazy loading的


第五种(枚举)
public enum Singleton
{
    INSTANCE;
    public oid whateverMethod()
    {
    }
}
这种方式是Effectie Java作者Josh Bloch提倡的方式,它不仅能避免多线程同步问题,而且还能防止反序列化后重新创建新的对象,可谓是很坚强的壁垒。不过1.5才引入的enum特性,用这种方式不免让人觉得生疏。

第六种(双重校验锁)
public class Singleton
{
    private volatile static Singleton singleton;
    public static Singleton getSingleton()
    {
        if(singleton == null)
        {
            synchronized(Singleton.class)
            {
                if(singleton == null)
                {
                    singleton = new Singleton();
                }
            }
        }
    }
    return singleton;
}
在JDK1.5之后,该方法才能正常达到单例效果


总结
有两个问题需要注意:
1、如果单例由不同的类装载器装入,那便有可能存在多个单例类的实例。假定不是远端存取,例如一些servlet容器对每个servlet使用完全不同的类装载器,这样的话如果有两个servlet访问一个单例类,他们就都会有各自的实例。

2、如果Singleton实现了java.io.Serializable接口,那么这个类的实例就可能被序列化和复原。不管怎样,如果你序列化一个单例类的对象,接下来复原多个该对象,就会有多个单例类的实例

对第一个问题的修复办法是:
private static Class getClass(String classname) throws ClassNotFoundException
{
    ClassLoader loader = Thread.currentThread().getContextClassLoader();
    if(null == loader)
    {
        loader = Singleton.class.getClassLoader();
    }
    return loader.loadClass(classname);
}

对第二个问题的修复办法是:
public class Singleton implements java.io.Serializable
{
    public static Singleton INTANCE = new Singleton();
   
    private Singleton()
    {
    }

    private Object readResolve()
    {
        return INSTANCE;
    }
}

你可能感兴趣的:(java,thread,多线程,工作,servlet)