一、如何理解執行緒安全
在多執行緒中稍微不注意就會出現執行緒安全問題,那么什么是執行緒安全問題?
我的認識是,在多執行緒下代碼執行的結果和預期的正確的結果不一致,該代碼就是執行緒不安全的,否則就是執行緒安全的
在深入理解Java虛擬機一書中看到的定義時
當多個執行緒訪問同一個物件時,如果不用考慮這些執行緒在運行環境下的調度和交替運行,也不需要進行額外的同步,或者在呼叫方進行任何其他的協調操作,呼叫這個物件的行為都可以獲取正確的結果,那么這個物件時執行緒的
在多執行緒條件下,多個執行緒肯定會相互協作完成一件事,一般來說就會涉及到多個執行緒將相互通信告知彼此狀態以及當前執行結果等,另外為了性能優化,還會涉及到編輯器指令重排序和處理器指令重排序
二、并發編程中的主要解決哪兩個問題
1、執行緒之間如何通信
通信是指執行緒之間以何種機制來交換資訊,主要有兩種:共享記憶體和訊息傳遞
2、執行緒之間如何完成同步(這里的執行緒指的是并發執行的活動物體)
Java記憶體模型是共享記憶體的并發模型,執行緒之間主要通過讀-寫共享變數來完成隱式通信,
三、JVM中的共享變數和執行緒獨占變數
共享變數
在Java中所有實體域,靜態域和陣列元素都是放在堆記憶體中(所有執行緒均可以訪問到,是可以共享的),
執行緒獨占
區域變數,方法定義引數和例外處理器引數不會在執行緒間共享
共享資料會出現執行緒安全的問題,而非共享資料不會出現執行緒安全的問題
四、描述一下JMM的抽象結構模型
我們知道CPU的處理速度和主存的讀寫速度不是一個量級的,為了平衡這種巨大的差距,每個CPU都會有快取,因此,共享變數會先放在主存中,每個執行緒都有屬于自己的作業記憶體,并且會把位于主存中的共享變數拷貝到自己的作業記憶體中,之后讀寫操作均使用位于作業記憶體的變數副本,并且在某個時刻將作業記憶體的變數副本寫到主存中去,JMM就從抽象層定義了這種方式,并且JMM決定了一個執行緒對共享變數的寫入何時對其他執行緒是可見的,

如圖為JMM抽象示意圖,執行緒A和執行緒B 之間要完成通信的話,要經理如下兩步:執行緒A從主記憶體中將共享變數讀入執行緒A 的作業記憶體后并進行操作,之后將資料重新寫會主記憶體中;執行緒B從主記憶體中讀取最新的共享變數,
從橫向去看,執行緒A和執行緒B好像通過共享變數在進行隱式通信,這其中就有個問題,如果執行緒A更新后資料并沒有及時的寫回,而此時執行緒B讀到了過期的資料,這就出現了臟讀現象,可以通過同步機制(控制不同執行緒操作發生的相對順序)來解決或者通過valatitl關鍵字是的每次volatitl變數都能夠強制重繪到主存,從而對每個執行緒都是可見的
五、由于JMM,多執行緒情況下可能出現哪些問題
從上面記憶體抽象結構來說,可能出現資料臟讀的現象,這就是資料可見性的問題,另外,重排序在多執行緒中不注意的話也容易存在一些問題,比如一個經典的問題DCL(雙重檢驗鎖),這就是需要禁止重排序,另外,在多執行緒下原子操作例如:i++不加注意也容易出現執行緒安全的問題,
單總的來說,在多執行緒開發時需要從原子性、有序性、可見性三個方面進行考慮,
J.U.C包下的并發工具類和并發容器也是需要花時間去掌握的,
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/79309.html
標籤:Java
