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

本文详细介绍了单例模式的六种实现方式,包括懒汉线程不安全、懒汉线程安全、饿汉式、静态内部类、枚举及双重校验锁等方法,并探讨了每种方法的特点和适用场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

第一种(懒汉,线程不安全)

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; 
} 

总结 
有两个问题需要注意: 
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; 
    } 
}

转载于:https://my.oschina.net/aidelingyu/blog/808191

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值