首頁 > Java > java教程 > 主體

java雙重檢驗鎖定模式是什麼

WBOY
發布: 2023-05-19 15:29:49
轉載
1477 人瀏覽過

起因

在對專案進行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 if 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
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板