首页  >  文章  >  Java  >  java双重检验锁模式是什么

java双重检验锁模式是什么

WBOY
WBOY转载
2023-05-19 15:29:491461浏览

起因

在对项目进行PMD静态代码检测时,遇到了这样一个问题

Partially created objects can be returned by the Double Checked Locking pattern when used in Java. An optimizing JRE may assign a reference to the baz variable before it calls the constructor of the object the reference points to.

Note: With Java 5, you can make Double checked locking work, if you declare the variable to be volatile.

可能在使用双重检验锁模式时,会返回一个未完全初始化的对象。有些人可能会怀疑部分初始化对象的概念,请继续往下分析

什么是双重检验锁模式

<code>public static Singleton getSingleton() {<br>    if (instance == null) {                        <br>        synchronized (Singleton.class) {<br>            if (instance == null) {                 <br>                instance = new Singleton();<br>            }<br>        }<br>    }<br>    return instance ;<br>}</code> 

我们看到,在同步代码块的内部和外部都判断了instance == null,这是因为,可能会有多个线程同时进入到同步代码块外的if判断中,如果在同步代码块内部不进行判空的话,可能会初始化多个实例。 

问题所在

这种写法看似完美无缺,但它却是有问题的,或者说它并不担保一定完美无缺。主要原因在于instance = new Singleton();并不是原子性的操作。
创建一个对象可以分为三部:

<code>1.分配对象的内存空间<br>2.初始化对象<br>3.设置instance指向刚分配的内存地址<br>当instance指向分配地址时,instance是不为null的</code> 

但是,2、3步之间,可能会被重排序,造成创建对象顺序变为1-3-2.试想一个场景:
线程A第一次创建对象Singleton,对象创建顺序为1-3-2;
当给instance分配完内存后,这时来了一个线程B调用了getSingleton()方法
这时候进行instance == null的判断,发现instance并不为null。
但注意这时候instance并没有初始化对象,线程B则会将这个未初始化完成的对象返回。那B线程使用instance时就可能会出现问题,这就是双重检查锁问题所在。 

使用volatile

对于上述的问题,我们可以通过把instance声明为volatile型来解决

<code>public class Singleton{<br>    private volatile static Singleton instance;<br>    public static Singleton getSingleton() {<br>        if (instance == null) {                        <br>            synchronized (Singleton.class) {<br>                if (instance == null) {                 <br>                    instance = new Singleton();<br>                }<br>            }<br>        }<br>        return instance ;<br>    }<br>}</code> 

但是必须在JDK5版本以上使用。 

静态内部类

<code>public class Singleton {  <br>    private static class SingletonHolder {  <br>        private static final Singleton INSTANCE = new Singleton();  <br>    }  <br>    private Singleton (){}  <br>    public static final Singleton getInstance() {  <br>        return SingletonHolder.INSTANCE; <br>    }  <br>}</code>

目前比较推荐的写法是采用静态内部类的方式,既能够实现懒加载,又不会出现线程安全问题。而且减少了synchronized的开销。

以上是java双重检验锁模式是什么的详细内容。更多信息请关注PHP中文网其他相关文章!

声明:
本文转载于:yisu.com。如有侵权,请联系admin@php.cn删除