单例模式

在实际应用中,线程池、缓存、日志对象、对话框对象常被设计成单例,总之,选择单例模式就是为了避免不一致状态。

下面实现几种单例模式

1.

    private static SingletonDemo instance = new SingletonDemo();
    private SingletonDemo(){};
    public SingletonDemo getInstance()
    {
        return instance;
    }

这种单例模式是饿汉模式,类加载的时候就会进行单例初始化。

2.

    private volatile static SingletonDemo2 instance;
    private SingletonDemo2(){};
    public SingletonDemo2 getInstance()
    {   
        if (instance == null)
        {
            synchronized (SingletonDemo2.class)
            {
                if (instance == null)
                {
                    instance = new SingletonDemo2();
                }
            }
        }
        return instance;
    }

这种考虑是线程安全与懒加载。需要注意一定要用 volatile 修饰单例变量,因为 instance = new SingletonDemo2();不是原子性的,这段话在JVM中会做三步完成

1.给instance分配内存

2.调用构造函数进行初始化

3.将instance对象指向分配的内存

问题在于JVM会有指令重排序,也就是说上述的  123 可能的执行结果为1-2-3 也可能是 1-3-2,  3执行完instance就不为null了,如果执行顺序是 1-3-2,实例化之前instance就已经是 非null 了,这时候其他线程进来判断 instance非空就直接返回了,就会造成问题。所以用volatile禁止指令重排序。


3.

 private SingletonDemo3(){};
    static class SingletonDemoInner
    {
        private static SingletonDemo3 INSTANCE = new SingletonDemo3();
    }
    public static  SingletonDemo3 getInstance()
    {
        return SingletonDemoInner.INSTANCE;
    }

这种利用了静态内部类进行懒加载。

以上三种有一个共同的缺点就是如果继承序列化类的时候需要重写readResolve方法,因为readResolve方法会调用类的默认构造函数实例化一个新的实例,这样就破坏了单例模式。还有就是反射不安全,这里不介绍了。

4.

public enum SingletonEnum
{
    INSTANCE;
    public void sunSomething()
    {
        System.out.println("Sun!");
    }
}

枚举类实现单例模式可以解决序列化问题也是线程安全的,但也是饿汉模式的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值