Java中的雙重檢查(Double-Check)詳解
在 Effecitve Java 一書的第 48 條中提到了雙重檢查模式,并指出這種模式在 Java 中通常并不適用。該模式的結(jié)構(gòu)如下所示:
public Resource getResource() {
if (resource == null) {
synchronized(this){
if (resource==null) {
resource = new Resource();
}
}
}
return resource;
}
該模式是對下面的代碼改進(jìn):
public synchronized Resource getResource(){
if (resource == null){
resource = new Resource();
}
return resource;
}
這段代碼的目的是對 resource 延遲初始化。但是每次訪問的時候都需要同步。為了減少同步的開銷,于是有了雙重檢查模式。
在 Java 中雙重檢查模式無效的原因是在不同步的情況下引用類型不是線程安全的。對于除了 long 和 double 的基本類型,雙重檢查模式是適用 的。比如下面這段代碼就是正確的:
private int count;
public int getCount(){
if (count == 0){
synchronized(this){
if (count == 0){
count = computeCount(); //一個耗時的計算
}
}
}
return count;
}
上面就是關(guān)于java中雙重檢查模式(double-check idiom)的一般結(jié)論。但是事情還沒有結(jié)束,因?yàn)閖ava的內(nèi)存模式也在改進(jìn)中。Doug Lea 在他的文章中寫道:“根據(jù)最新的 JSR133 的 Java 內(nèi)存模型,如果將引用類型聲明為 volatile,雙重檢查模式就可以工作了”。所以以后要在 Java 中使用雙重檢查模式,可以使用下面的代碼:
private volatile Resource resource;
public Resource getResource(){
if (resource == null){
synchronized(this){
if (resource==null){
resource = new Resource();
}
}
}
return resource;
}
當(dāng)然了,得是在遵循 JSR133 規(guī)范的 Java 中。
所以,double-check 在 J2SE 1.4 或早期版本在多線程或者 JVM 調(diào)優(yōu)時由于 out-of-order writes,是不可用的。 這個問題在 J2SE 5.0 中已經(jīng)被修復(fù),可以使用 volatile 關(guān)鍵字來保證多線程下的單例。
public class Singleton {
private volatile Singleton instance = null;
public Singleton getInstance() {
if (instance == null) {
synchronized(this) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
推薦方法 是Initialization on Demand Holder(IODH),
public class Singleton {
static class SingletonHolder {
static Singleton instance = new Singleton();
}
public static Singleton getInstance(){
return SingletonHolder.instance;
}
}
以上就是本文的全部內(nèi)容,希望對大家學(xué)習(xí)java程序設(shè)計有所幫助。
相關(guān)文章
IDEA?Ui設(shè)計器JFormDesigner?永久激活插件+注冊機(jī)(親測一直在用)
這篇文章主要介紹了IDEA?Ui設(shè)計器JFormDesigner?永久激活----插件+注冊機(jī)?自己一直在用的版本和注冊機(jī),非常不錯,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),需要的朋友可以參考下2022-08-08
Java 面向?qū)ο笾^承篇詳解原理與特點(diǎn)
繼承是java面向?qū)ο缶幊碳夹g(shù)的一塊基石,因?yàn)樗试S創(chuàng)建分等級層次的類。繼承就是子類繼承父類的特征和行為,使得子類對象(實(shí)例)具有父類的實(shí)例域和方法,或子類從父類繼承方法,使得子類具有父類相同的行為2021-10-10
Java工具jsch.jar實(shí)現(xiàn)上傳下載
這篇文章主要為大家詳細(xì)介紹了Java操作ftp的一款工具,利用jsch.jar針對sftp的上傳下載工具類,具有一定的參考價值,感興趣的小伙伴們可以參考一下2018-12-12
Java 線程池詳解及創(chuàng)建簡單實(shí)例
這篇文章主要介紹了Java 線程池詳解及創(chuàng)建簡單實(shí)例的相關(guān)資料,需要的朋友可以參考下2017-02-02
springboot如何獲取接口下所有實(shí)現(xiàn)類
這篇文章主要介紹了springboot如何獲取接口下所有實(shí)現(xiàn)類問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-09-09
java中InputStream轉(zhuǎn)為MultipartFile的解決方案
這篇文章主要介紹了java中InputStream轉(zhuǎn)為MultipartFile的解決方案,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2025-03-03
SpringBoot通過整合Dubbo解決@Reference注解問題
這篇文章主要介紹了SpringBoot通過整合Dubbo解決@Reference注解問題,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2020-03-03

