两种创建单例模式的方式

Posted by hcy on December 10, 2019

两种创建懒汉式单例模式的方法

​ 先前使用findBug扫描了一下项目,发现单例的创建被提示警告了,根据其给的连接,以下两种创建单例模式的方式是正确的。

第一种,使用静态辅助类来创建

1
2
3
4
5
6
7
8
//返回单例对象
public Object singleton2() {    
    return SingletonHelp.INSTANCE;
}

private static class SingletonHelp {    
    static Object INSTANCE = new Object();
}

使用一个静态的类,类中静态变量INSTANCE为我们需要创建的单例实例,因为静态变量的初始化是在类初次加载进来时初始化的,他优先于程序线程的执行,所以其能保证并发情况下单例成立。

第二种,使用双重检测+volatile关键字创建

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
    private volatile Object o;

    public Object singleton1() {
        Object temp = o;
        if (temp == null) {
            synchronized (this) {
                temp = o;
                if (temp == null) {
                    o = temp = new Object();
                }
            }
        }
        return o;
    }

我们常用双重检测来创建单例模式,这个很好理解,如果对象为null则先加锁再创建,如果不为null则直接返回实例,从而实现对象的单例。但是如果忘记使用volatile关键字修饰对象,则可能会导致错误 。

因为当程序执行到 o = new Object();这一行时,期望的是先new Object(),再将创建好的对象赋值给o。但实际上当发生指令重排序时,会先执行引用的赋值操作,后执行创建对象操作,也是有可能发生的。

这将导致后面的线程判断o!=null 返回true,但此时对象还没有创建成功,拿到的是一个半成品,导致问题。导致了不完整的对象被发布出去。

当加入volatile修改对象时,避免了指令重排序,所以创建的对象时可靠的。


转载请注明出处:https://www.huangchaoyu.com/2019/12/10/两种创建单例模式的方式/