1. 程式人生 > >Java併發程式設計的藝術——原子操作的實現原理

Java併發程式設計的藝術——原子操作的實現原理

原子操作的定義

atomic,表面上,指的是不能進一步分割的最小粒子。借鑑我們在資料庫中學的事務的概念,atomic operation,意為——不可被中斷的一個或者一系列操作。

處理器如何實現原子操作

使用匯流排鎖保證原子性

如果多個處理器同時對共享變數進行讀改寫操作,例如,i++操作,那麼共享變數會被多個處理器同時操作,這樣讀改寫操作就不是原子的了。例如,cpu1將共享變數i=1讀到自己的快取,與此同時,cup2將i=1也讀入了了自己的快取,cup1 和cpu2在各自讀到的i=1的基礎上進行++操作,之後再寫回系統記憶體中,此時i=2,兩次自加操作,並沒有讓i=3。 要想保證讀寫改一個變數的操作是原子的,就必須保證CUP1讀寫改共享變數的時候,CUP2不能操作快取了該共享變數記憶體地址的快取。 處理器使用匯流排鎖就是來解決這個問題的。匯流排鎖就是使用處理器提供的一個LOCK訊號,當一個處理器在總線上輸出此訊號時,其他處理器的請求將被阻塞住,那麼該處理器可以獨佔共享記憶體。

使用快取鎖定來保證原子性

在同一時刻,我們只需要保證對某個記憶體地址的操作是原子性即可,但匯流排鎖定把CUP和記憶體之間的通訊鎖住了,這使得鎖定期間,其他處理器不能操作其他記憶體地址的資料,所以匯流排鎖定的開銷比較大,目前處理器在某些場合下使用快取鎖定代替匯流排鎖定來進行優化。

Java如何實現原子操作

使用迴圈CAS實現原子操作

JVM中的CAS操作正是利用了處理器提供的CMPXCHG指令來實現的。自旋CAS實現的基本思路就是迴圈進行CAS操作直到成功為止。

cas實現原子操作的三大問題

  • ABA問題 cas需要再操作值的時候,檢查值有沒有發生變化,如果沒有發生變化則更新。但是一個值,如果原來為A,變成了B,又變成了A,那麼使用CAS進行compare and set的時候,會發現它的值根本沒變化過,但實際上是變化過的。ABA問題的解決思路就是使用版本號,1A->2B->3C。在Atomic包中(above 1.5),提供了一個AtomicStampedReference來解決ABA問題。
  • 迴圈時間開銷大 自選CAS如果長時間不成功,會給CUP帶來非常大的執行開銷。
  • 只能保證一個共享變數的原子操作 (above 1.5)提供了AtomicReference類來保證引用物件之間的原子性,可以將多個變數放在一個物件裡進行cas操作。

使用鎖實現原子操作

鎖機制保證了只有獲得鎖的執行緒才能操作鎖定的記憶體區域。JVM內,實現了很多鎖機制,有偏向鎖,輕量級鎖,互斥鎖。除了偏向鎖,JVM實現鎖的方式都使用了迴圈CAS,即當一個執行緒想進入同步快的時候使用迴圈CAS的方式來獲取鎖,當它退出同步快的時候使用CAS釋放鎖。