知識梳理系列之三——同步鎖、三大性質等併發編程要點

知識梳理系列之三——同步鎖、三大性質等併發編程要點

三大性質

  1. 原子性

用來保證一個程序操作被完整的執行,因爲在CPU中是一條條指令執行,一個編碼操作可能需要執行多條指令,具備原子性的操作,要麼完整的被執行,要麼不執行;

單純的賦值、讀取操作是原子操作,多個原子操作結合在一起就是非原子操作。
多個操作要保證原子性就需要使用Synchronized關鍵字和Lock機制

  1. 有序性

保證程序的邏輯先後順序;

與指令重排有關

  1. 可見性

在共享數據被多線程使用時,各個線程的任務執行前,CPU會一次讀取數據並保存CPU高速緩存中,如果某個線程修改了此共享數據的值(往往還保存在CPU高速緩存中,主存中還沒來得及更新,或者更新了別的線程已經讀取過了不清楚值的更改),這就是著名的數據不一致問題。
可見性就是使得共享數據發生變化後立即更新主存並通知其他使用該變量的線程,將緩存中的數據置爲無效。

CPU爲什麼需要高速緩存:
在計算機中,數據處理需要CPU與內存協作,但是內存(又稱之爲主存)的讀寫速度遠低於CPU的處理速度,爲了能夠很好的協作,CPU中有一塊高速緩存的區域,用於將要處理的數據從內存(主存)中讀取出來並存儲在CPU高速緩存中,然後CPU執行數據處理完成後,再重新刷新內存(主存)中存儲的數據

附:數據不一致問題還有一種解決方式:總線鎖,不過這樣會導致CPU在訪問共享數據阻塞效率不夠好。


指令重排

CPU:執行由編碼器輸出的指令,若一條指令時阻塞或需要等待的,CPU並不會阻塞,而是執行其他的非邏輯相關指令或者將時間片分配給別的程序。

編碼器:在編譯器編譯程序源碼成指令時,會在保證程序邏輯不改變的前提下優化指令的順序。
這種編譯器優化指令的操作就是指令重排。
保障原子性,就是避免指定的操作被重排而是保持編寫順序的一種手段。通常以Atomic開頭的變量表示原子操作變量

volatile關鍵字

volatile關鍵字就是保證被修飾變量的可見性和部分有序性的一個修飾符
被volatile修飾的變量一般是共享變量,即多線程訪問、修改的變量,修飾後保證此變量被修改後,立即更新主存,並且通知已經讀取準備進行操作的其他線程CPU緩存數據無效。

同步鎖Synchonized

Synchonized關鍵字修飾位置有兩個:

  1. 修飾方法(同步方法);
  2. 修飾代碼塊(同步代碼塊)。

兩者之間的區別是作用域不相同,修飾方法時,整個方法需要同步,多線程進入時必須獲取鎖,持有鎖的線程可進入執行,執行完成釋放鎖後,其他線程纔可以獲取鎖進入。

根據鎖的類型有可以分爲兩種:

  1. 類對象鎖:修飾靜態方法、修飾代碼塊時傳入.class作爲鎖
  2. 對象鎖:修飾成員方法、修飾代碼塊傳入this作爲鎖或者其他對象的實例作爲鎖

類對象鎖,凡是這個類的實例都需要獲取鎖才能執行,此類多個實例都需同步;
對象鎖只針對同一個實例,需要獲取鎖;
同一實例進入對象鎖時,有序執行,雖然獲取鎖的線程是隨機的;
不同實例進入對象鎖時,無序互不影響,多線程多實例所持對象鎖不同,互不影響結果。
同一實例/不同實例進入類對象鎖,有序執行;

wait/sleep/notify/notifyAll

wait與sleep的區別

  1. wait是Object的方法,sleep是Thread的方法;
  2. wait時,會釋放持有的當前線程的鎖,而sleep不會是釋放,將持鎖直到超時;
  3. wait傳入一個超時時間,並不一定會立即獲得資源,取決於其他線程是否釋放資源,以及wait是否能搶到資源;
  4. wait不設置超時時間必須由notify/notifyAll喚醒,多個Object wait時,需要使用notifyAll避免死鎖,因爲notify是隨機喚醒的。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章