高併發程式設計-02-併發程式設計存在的風險
多執行緒的高併發程式設計提高了我們的CPU利用率及簡化開發模式,但是又同時給我們帶來了風險,使用不當就會有風險,那到底有什麼風險?我們來看看
1,執行緒的安全性問題
假設,我現在編寫了一個程式,來儲存系統的訪問量,如何實現呢?
很簡單,我可以設定一個全域性變數,然後,每次使用者訪問一次系統,我就自增1,那麼這個程式應該是這樣寫的,如下:
public class System {
private int count;
public int getCount(){
return count++;
}
}
這段程式碼,大家覺得有沒有問題?
如果在單執行緒的模式下,沒問題,但是在多執行緒的模式下,會有問題,為什麼?
因為其中一個關鍵的步驟,count++不是一個原子操作,這個操作實際會分為三個步驟,
分別是,讀取count值,給count值+1,將結果寫到count值上。
那麼大家想想,當我們有多個執行緒同時訪問這個資源的時候,會出現什麼情況?
這就是我們說的執行緒安全問題。
如果解決此類問題,java給我們提供一種同步機制,你只需要這麼做就可以解決問題:
public synchronized int getCount(){
return count++;
}
好了,接下來,我們來說會出現的第二類問題
2,活躍性問題
比如,死鎖,飢餓,活鎖,這些都是屬於活躍性問題。當某個操作無法繼續執行時,這就是活躍性問題,我舉個死鎖的例子,比如我老婆跟我分工家務活,要求我先拖地,她就洗碗,而我要求她先洗碗,我再拖地,那麼這個時候,我們彼此手握對方進行下一步工作的開啟條件,但都彼此不願意先動手,於是就陷入了僵局,這就是死鎖。
換成程式的說法,就是A執行緒需要等待的鎖被B執行緒佔用,而B執行緒需要的等待的鎖被A執行緒佔用,所以相互都不釋放,於是就陷入了死鎖。
更多問題,我們後續繼續講解
3,效能問題
效能問題,你肯定會有疑問,多執行緒不就是為了提高系統的吞吐量嗎?怎麼還有效能問題?
這個原因很簡單,還是那句話,你沒有正確使用
下面我們來看看多執行緒可能帶來的效能問題有哪些?
當我們採用多執行緒程式設計時,每個執行緒會由CPU實現排程,分配一定的時間片,那這個時候,排程器就會頻繁掛起一個活躍的執行緒轉而執行另一個執行緒,這就是我們說的“上下文切換”,這種操作將會帶來極大的開銷。
還有一個問題,當CPU重新切換回之前活躍的執行緒時,執行緒是否要繼續之前未完成的操作,答案是必須的,那麼就需要做一件事,在CPU切換的時候,儲存執行緒的執行狀態,這又是一筆開銷。
最後,還有一種情況,就是多執行緒共享有狀態的資料時,需要使用同步機制來保證資料安全,而這些機制會抑制編譯器的某些優化,比如使得記憶體緩衝區中的資料失效等等,以及增加共享記憶體匯流排的同步流量
所以,有個重要的問題,一般我們的程式開啟多少執行緒合適?
當然不是越多越好,大家可以留言,說說你的答案