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;
}
該模式是對(duì)下面的代碼改進(jìn):
public synchronized Resource getResource(){
if (resource == null){
resource = new Resource();
}
return resource;
}
這段代碼的目的是對(duì) resource 延遲初始化。但是每次訪問的時(shí)候都需要同步。為了減少同步的開銷,于是有了雙重檢查模式。
在 Java 中雙重檢查模式無效的原因是在不同步的情況下引用類型不是線程安全的。對(duì)于除了 long 和 double 的基本類型,雙重檢查模式是適用 的。比如下面這段代碼就是正確的:
private int count;
public int getCount(){
if (count == 0){
synchronized(this){
if (count == 0){
count = computeCount(); //一個(gè)耗時(shí)的計(jì)算
}
}
}
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)時(shí)由于 out-of-order writes,是不可用的。 這個(gè)問題在 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;
}
}
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家學(xué)習(xí)java程序設(shè)計(jì)有所幫助。
相關(guān)文章
詳解spring boot實(shí)現(xiàn)websocket
這篇文章主要介紹了詳解spring boot實(shí)現(xiàn)websocket,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-06-06
java實(shí)現(xiàn)OpenGL ES紋理映射的方法
這篇文章主要介紹了java實(shí)現(xiàn)OpenGL ES紋理映射的方法,以實(shí)例形式較為詳細(xì)的分析了紋理映射的實(shí)現(xiàn)技巧,需要的朋友可以參考下2015-06-06
基于RocketMQ實(shí)現(xiàn)分布式事務(wù)的方法
了保證系統(tǒng)數(shù)據(jù)的一致性,我們需要確保這些服務(wù)中的操作要么全部成功,要么全部失敗,通過使用RocketMQ實(shí)現(xiàn)分布式事務(wù),我們可以協(xié)調(diào)這些服務(wù)的操作,保證數(shù)據(jù)的一致性,這篇文章主要介紹了基于RocketMQ實(shí)現(xiàn)分布式事務(wù),需要的朋友可以參考下2024-03-03
Java實(shí)現(xiàn)向Word文檔添加文檔屬性
這篇文章主要介紹了Java實(shí)現(xiàn)向Word文檔添加文檔屬性的相關(guān)資料,需要的朋友可以參考下2023-01-01

