欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

(转载)java单例模式的6种写法

程序员文章站 2022-04-09 07:54:10
...
第一种(懒汉,线程不安全)
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;
    }
}