上邊關於逸出的概念講述的很是模糊,下面列舉幾個逸出的示例。
通過靜態變數引用逸出
public static setknownsecrets;
public void initialize()
上邊**示例中,呼叫initialize方法,發布了knowsecrets物件。當你向knowsecrets中新增乙個secret時,會同時將secret物件發布出去,原因是可以通過遍歷knowsecrets獲取到secret物件的引用,然後進行修改。
通過非靜態(私有)方法
class unsafestates ;
public string getstates()
}
以這種方式發布的states會出問題,任何乙個呼叫者都能修改它的內容。陣列states已經逸出了它所屬的範圍,這個本應該私有的資料,事實上已經變成共有的了。
this逸出
public class thisescape
});}}
在上邊**中,當我們例項化thisescape物件時,會呼叫source的registerlistener方法時,便啟動了乙個執行緒,而且這個執行緒持有了thisescape物件(呼叫了物件的dosomething方法),但此時thisescape物件卻沒有例項化完成(還沒有返回乙個引用),所以我們說,此時造成了乙個this引用逸出,即還沒有完成的例項化thisescape物件的動作,卻已經暴露了物件的引用,使其他執行緒可以訪問還沒有構造好的物件,可能會造成意料不到的問題。
通過上述示例,個人理解,對逸出的概念應該定義為:
乙個物件,超出了它原本的作用域,而可以被其它物件進行修改,而這種修改及修改的結果是無法**的。換句話說:乙個物件發布後,它的狀態應該是穩定的,修改是可被檢測到的。如果在其它執行緒修改(或做其它操作)乙個物件後導致物件的狀態未知,就可以說這個物件逸出了。總之,乙個物件逸出後,不論其它執行緒或物件是否使用這個逸出的物件都不重要,重要的是,被誤用及被誤用後的未知結果的風險總是存在的。
ps 書中給出了避免this逸出的方法:
public class safelistener };}
public static safelistener newinstance(eventsource source)
}
在這個構造中,我們看到的最大的乙個區別就是:當構造好了safelistener物件之後,我們才啟動了監聽執行緒,也就確保了safelistener物件是構造完成之後在使用的safelistener物件。
對於這樣的技術,書裡面也有這樣的注釋:
具體來說,只有當建構函式返回時,this引用才應該從執行緒中逸出。建構函式可以將this引用儲存到某個地方,只要其他執行緒不會在建構函式完成之前使用它。
/**
* 懶漢模式(執行緒不安全)
* 單例例項在第一次使用時進行建立
*/@notthreadsafe
public class singletonexample1
// 單例物件
private static singletonexample1 instance = null;
// 靜態的工廠方法
public static singletonexample1 getinstance()
return instance;}}
懶漢模式本身是執行緒不安全的,如果想要實現執行緒安全可以通過synchronized關鍵字實現:
/**
* 懶漢模式
* 單例例項在第一次使用時進行建立
*/@threadsafe
@notrecommend
public class singletonexample3
// 單例物件
private static singletonexample3 instance = null;
// 靜態的工廠方法
public static synchronized singletonexample3 getinstance()
return instance;}}
但此中方式不推薦使用,應該它通過同一時間內只允許乙個執行緒來訪問的方式實現執行緒安全,但是卻帶來了效能上面的開銷。
我們可以通過以下方式來實現執行緒安全:
懶漢模式 -》 volatile + 雙重同步鎖單例模式
/**
* 懶漢模式 -》 雙重同步鎖單例模式
* 單例例項在第一次使用時進行建立
*/@threadsafe
public class singletonexample4
// 1、memory = allocate() 分配物件的記憶體空間
// 2、ctorinstance() 初始化物件
// 3、instance = memory 設定instance指向剛分配的記憶體
// jvm和cpu優化,發生了指令重排(多執行緒 )
// 1、memory = allocate() 分配物件的記憶體空間
// 3、instance = memory 設定instance指向剛分配的記憶體
// 2、ctorinstance() 初始化物件
// 單例物件 volatile + 雙重檢測機制 -> 禁止指令重排
private volatile static singletonexample4 instance = null;
public static singletonexample4 getinstance() }}
return instance;}}
/**
* 餓漢模式
* 單例例項在類裝載時進行建立
*/@threadsafe
public class singletonexample2
// 單例物件
private static singletonexample2 instance = new singletonexample2();
// 靜態的工廠方法
public static singletonexample2 getinstance()
}
餓漢模式不會有執行緒問題,但是在類載入時例項化物件。使用時要考慮兩點:
私有建構函式在使用時沒有過多的邏輯處理(銷毀效能,慢)
這個物件一定會被使用(浪費資源)
在靜態**塊中例項化乙個物件:
/**
* 餓漢模式
* 單例例項在類裝載時進行建立
*/@threadsafe
public class singletonexample6
// 單例物件
private static singletonexample6 instance = null;
static
// 靜態的工廠方法
public static singletonexample6 getinstance()
public static void main(string args)
}
列舉模式:
/**
* 列舉模式:最安全
*/@threadsafe
@recommend
public class singletonexample7
public static singletonexample7 getinstance()
private enum singleton
public singletonexample7 getinstance() }}
java併發學習 讀書筆記二
executor框架介紹 1 executor框架提供了乙個靈活的執行緒池實現,防止應用程式過載而耗盡記憶體。它是基於生產者 消費者模式的,提交任務的執行緒是生產者,執行任務的執行緒是消費者。2 執行緒池 newfixedthreadpool建立乙個定長的執行緒池,每當提交乙個任務就建立乙個執行緒,...
併發學習(十) 安全物件發布
平時我們建立的物件往往不會考慮到安全物件的概念,這可能比較陌生,但是你面試的時候面試官很喜歡問你執行緒安全的單例模式,而這就是相關的知識點 發布 使物件能夠在除了當前作用域之外的地方使用 最常用的方法 將物件的引用儲存到乙個公有的靜態變數中,讓任何類和執行緒都能看到該物件。逸出 某個物件不應該被發布...
Java併發學習筆記(8 發布逸出
發布逸出 1 發布 發布是指將乙個物件,使其引用儲存到乙個其他 可以訪問到的地方,在乙個非私有方法返回這個引用,也可以把它傳遞到其他物件中.a 發布最簡單的就是將物件設定到公共靜態域中 b 發布第二種簡單的方式就是在乙個公共方法內直接return 物件的引用 第三種的發布就很隱秘了.就是講自身的物件...