java
parallelism
concurrency
程序(process)就是電腦中的一個正在執行的程式,其記憶體空間都是獨立的,彼此不會互相影響,也無法互相存取,一個作業系統內,通常會有多個程序同時在進行;而執行緒(thread)則是程序內的一個流程,Java程序內由main()開始,則是一個執行緒的開始,一直執行到程式碼的最後一行,執行緒結束後,就代表該程序也結束了;一個程序內至少會有一個執行緒,而且透過Thread物件,可以產生多個執行緒,進行不同的程式流程。
Thread(執行緒)可以用來開發,concurrency(並行)以及parallelism(平行)的程式;執行緒讓一個程序(process)可以「同時」進行多個流程,並共享同一個記憶體空間。
通常有以下幾種情況會使用到執行緒:
建立執行緒有幾種方式:
執行緒開始執行後,因為是同時進行,每個執行緒會拿到多少CPU時間是不可控的,所以完成的順序每次執行程式可能都會不一樣,而且當執行緒會操作同一個變數的時候,有可能因為同時修改,造成資料遺失,因此需要有一些機制來避免照些情況發生。
有一程式如下要做0~9數字相加:
會輸出:
注意
該範例是直接呼叫run()方法來執行相加的動作,所以只是方法名稱跟執行緒的run()依樣,但並非啟動執行緒,因為該類別也沒有繼承自Thread類別。
為了提升效能,改成多執行緒版本:
該範例加上了:
執行效能變快了,但會發現輸出都是:
這是因為啟動執行序後,主執行緒就會繼續往下執行,因為子執行緒都還沒執行完畢主執行緒就結束了,因次不會有計算結果發生。
因此在子執行緒啟動後,主執行緒需要暫停,等子執行緒執行完畢再繼續往下進行。
Thread的join()方法,可以讓主執行緒停在該行,等執行緒結束才繼續往下執行。
加了join()後,可以看到計算後的結果了。
注意
不要在呼叫start()啟動執行緒後就馬上做join(),這樣的話,就相當於執行緒執行結束後才會再啟動下一個新的執行緒,如此就沒有多執行緒同時執行的效果了,也就是效果會跟單執行緒一樣。
但有另外一個問題,每次計算的結果都不一樣,這是因為App.sum += i;
在底層其實是分成三個動作,取值、相加、存值,因為執行緒都會操作到同一個變數,在進行到哪一個動作都可能被中斷,因為有可能出現多個執行緒都取到同一個值然後計算完畢後存值互相去覆蓋了,造成計算結果出現問題,這種情況又稱為Race condition(競爭條件)。
因此我們需要對會被操作的App.sum
變數做鎖定的動作,不能同時被多個執行緒存取。
使用synchronized關鍵字鎖住物件:
將輸出正確結果: