java併發(一)執行緒安全概念
阿新 • • 發佈:2019-01-23
java中包含幾種執行緒級別:
不可變:這種級別是最簡單的執行緒安全方式,即:如果帶有狀態的變數是基本資料型別定義成final,是引用型別,則其物件不能有改變自身的行為
(如String,enum,Number的部分子類:Integer,Long等[不包括AtomicInteger,AtomicLong等])
絕對安全:不論執行環境如何,呼叫者都不需要任何額外的措施來保證執行緒安全,要想達到這點,可能會付出巨大的代價。
相對安全:對物件的單獨操作是執行緒安全的(如上面多執行緒訪問remove方法,add方法),但對於特定順序的連續呼叫,就需要呼叫者使用額外的同步手段來保證執行緒安全。
以java.util.Vector舉例,在java中稱它為執行緒安全的物件,這是因為Vector中所有的行為都被synchronized修飾,這也是java通俗意義上講的執行緒安全的概念,然而Vector實際上只是執行緒相對安全的,並非絕對安全,在涉及特定順序的連續呼叫就會出現問題:
/*
此程式先對Vector初始化1000個元素,然後每次開啟2個執行緒,1個執行緒執行刪除元素操作,1個執行緒執行獲取元素操作。
當一個錯誤的時機(獲取執行緒進入for迴圈執行到當前Vector的size-x時,被刪除執行緒搶走執行權刪除了x個或以上的元素)
此時獲取執行緒才得到執行權,結果此前的Vector的長度已經不夠size-x,就會導致角標越界異常。
*/
private static Vector<Integer> v = new Vector<>();
static{
for(int i=0; i<1000; i++){
v.add(i);
}
}
public static void main(String[] args) {
while(true){
new Thread(new Runnable() {
@Override
public void run() {
for(int i=0; i<v.size(); i++){
v.remove(i);
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
for(int i=0; i<v.size(); i++){
v.get(i);
}
}
}).start();
//不要產生過多的執行緒,防止作業系統假死
if(Thread.activeCount()>20)break;
}
}
執行緒相容:指物件本身不是執行緒安全的,但是呼叫者可以通過正確的同步手段來保證執行緒安全,也就是我們通常說的執行緒不安全。
執行緒對立:指物件無論是否採用同步操作,都無法在多執行緒中併發使用的程式碼,由於java天生具備多執行緒特性,這種情況很少見,且通常是有害的,應當儘量避免。
(常見的有Thread物件的resume方法和suspend方法[已廢棄],System的setIn,setOut,runFinalizersOnExit)