天天看點

Java并發程式設計第一記——volatile與synchronized

1. volatile

允許共享變量,它保證每一個線程看到變量的值都是一緻的,是輕量級的synchronized。其實作原理是CPU的LOCK指令,這個指令會做兩件事:将目前處理器中的緩存行(緩存最小配置設定機關)回寫到記憶體中和使其它處理器的緩存行失效。

2. synchronized

通過鎖的方式來實作同步。Java裡面有三種鎖:偏向鎖、輕量級鎖、重量級鎖(級别依次升高)。當通路同步塊時必須獲得鎖,鎖的資訊存儲在Java對象頭中。

  • 偏向鎖:最低級别的鎖,jvm預設開啟。這個鎖為了解決以下這個問題:當一個同步塊,本身競争不是很多,被一個線程反反複複的使用,那麼這個線程将會每次都會通過CAS(比較再交換)來獲得鎖,同步塊也會每次都加鎖。這個開銷是很大的,為了解決這個現象,引入了偏向鎖——即記錄線程ID,如果有偏向鎖,且指向的是正要通路的線程的ID,那麼将不會解鎖,而是直接獲得通路權限,之後也不會頻繁解鎖,大大減少開支。
  • 輕量級鎖:簡單點說,就是不會阻塞線程,而是會進行自旋操作,多次嘗試獲得鎖。經過多次嘗試之後,便會更新成重量級鎖,阻塞線程,注意更新之後不會降級。自旋操作會消耗CPU資源,但是,有了自旋會大大提高線程的響應時間。
  • 重量級鎖:沒有鎖的線程,會等待其它線程釋放鎖才能繼續進行,最進階别的鎖。

3. 補充

  • 原子操作:不可中斷的一個或一系列動作或指令。CPU實作原子操作是加鎖,總線上鎖或者緩存行上鎖。
  • CAS:比較再交換,目前值沒有發生變化,如果舊值發生變化,不更新新值,否則更新。舊值變化,說明已經修改了,保證同步,不更新成新值。
  • Java使用鎖和循環 CAS來實作原子操作。除了偏向鎖,其它Java實作同步都使用了循環CAS,但是其循環開銷大,ABA問題和隻能保證一個一個變量的問題還是有的。