多線程學習(5)volatile 和 synchronized 的區別

知足同步三個基本條件:

1.原子性緩存

原子性是指操做是不可分的。其表如今於對於共享變量的某些操做,應該是不可分的,必須連續完成。例如a++,對於共享變量a的操做,實際上會執行三個步驟,1.讀取變量a的值  2.a的值+1  3.將值賦予變量a 。 這三個操做中任何一個操做過程當中,a的值被人篡改,那麼都會出現咱們不但願出現的結果。因此咱們必須保證這是原子性的。多線程

2.可見性:一個線程對共享變量值得修改,可以及時的被其餘線程看到 併發

多線程高併發中,線程之間的通訊是靠內存共享,即一個對象或變量,它在堆中的主內存中,每個請求能夠看作一個線程,每個線程,都想操做這個主內存的對象或變量,線程會複製一份主內存中的對象或變量,到本身的線程本地棧內存中,直到操做完畢,纔會將本地棧內存的對象或變量,賦值給主內存。若是不加同步鎖,主內存中的對象或變量,值就容易被最後提交操做的線程覆蓋,發生錯誤。高併發

3.有序性:性能

指令重排序:代碼書寫的順序與實際執行的順序不一樣,指令重排序是編譯器或處理器爲了提升程序性能而作的優化。優化

1.編譯器優化的重排序(編譯器優化)spa

2.指令級並行重排序(處理器優化)線程

3.內存系統的重排序(處理器優化)對象

是否是全部的語句的執行順序均可以重排呢?

答案是否認的。爲了講清楚這個問題,先講解另外一個概念:數據依賴性blog

什麼是數據依賴性?

若是兩個操做訪問同一個變量,且這兩個操做中有一個爲寫操做,此時這兩個操做之間就存在數據依賴。數據依賴分下列三種類型:

名稱 代碼示例 說明
寫後讀 a = 1;b = a; 寫一個變量以後,再讀這個位置。
寫後寫 a = 1;a = 2; 寫一個變量以後,再寫這個變量。
讀後寫 a = b;b = 1; 讀一個變量以後,再寫這個變量。

上面三種狀況,只要重排序兩個操做的執行順序,程序的執行結果將會被改變。因此,編譯器和處理器在重排序時,會遵照數據依賴性,編譯器和處理器不會改變存在數據依賴關係的兩個操做的執行順序。也就是說:在單線程環境下,指令執行的最終效果應當與其在順序執行下的效果一致,不然這種優化便會失去意義。這句話有個專業術語叫作as-if-serial semantics (as-if-serial語義)

int num1=1;//第一行
int num2=2;//第二行
int sum=num1+num;//第三行

單線程:第一行和第二行能夠重排序,但第三行不行

重排序不會給單線程帶來內存可見性問題

多線程中程序交錯執行時,重排序可能會照成內存可見性問題。

 

synchronized關鍵字

synchronized經過操做對象鎖和類對象鎖,修飾方法和代碼塊,則保證持有鎖的線程操做完畢,從新賦值主內存中的對象或變量後,其餘線程再去爭搶鎖,繼續操做主內存對象。達到一個線程的執行結果對其餘線程的。知足上面的三個原則。

 

volatile變量每次被線程訪問時,都強迫從主內存中讀取該變量的值,而當變量發生變化的時候都會強迫線程將最新的值刷新到主內存中。

這樣不一樣的變量總能看到最新的值。

能夠把volatile變量的單個讀寫,當作是使用同一個鎖對這些單個讀/寫操做作了同步。

volatile關鍵字:

  • 可以保證volatile變量的可見性
  • 只能保證單個volatile變量的原子性,對於volatile++這種複合操做不具備原子性
  • 對volatile變量執行寫操做時,會在寫操做後加入一條store屏障指令

    • store指令會在寫操做後把最新的值強制刷新到主內存中。同時還會禁止cpu對代碼進行重排序優化。這樣就保證了值在主內存中是最新的。
  • 對volatile變量執行讀操做時,會在讀操做前加入一條load屏障指令

    • load指令會在讀操做前把內存緩存中的值清空後,再從主內存中讀取最新的值。

 

 

synchronized和volatile的比較:

  • synchronized鎖住的是變量和變量的操做,而volatile鎖住的只是變量,並且該變量的值不能依賴它自己的值,volatile算是一種輕量級的同步鎖
  • volatile不須要加鎖,比synchronized更加輕量級,不會阻塞線程。
  • 從內存可見性角度講,volatile讀至關於加鎖,volatilexie至關於解鎖。
  • synchronized既能保證可見性,又能保證原子性,而volatile只能保證可見性,沒法保證原子性。

注:因爲voaltile比synchronized更加輕量級,因此執行的效率確定是比synchroized更高。在能夠保證原子性操做時,能夠儘可能的選擇使用volatile。在其餘不能保證其操做的原子性時,再去考慮使用synchronized。

相關文章
相關標籤/搜索