1、處理器的原子性 java
處理器使用基於對緩存加鎖或者總線加鎖的方式來實現多處理器之間的原子操做。首先處理器會自動保證基本的內存操做的原子性。處理器保證從系統內存中讀取或者寫入一個字節是原子的。緩存
複雜的內存操做處理器是不能自動保證其原子性的,好比跨總線寬度、跨多個緩存行和跨頁表的訪問。處理器提供總線鎖定和緩存鎖定兩個機制來保證。併發
1.使用總線鎖保證原子性工具
第一個機制是經過總線鎖保證原子性。若是多個處理器同時對共享變量進行讀改寫操做(i++就是經典的讀改寫操做),那麼共享變量就會被多個處理器同時進行操做,這樣讀改寫操做就不是原子操做的,操做完成以後共享變量的值會和指望的不一致。優化
處理器使用總線程鎖就是解決這個問題的。所謂總線程鎖就是使用處理器提供的一個LOCK#信號,當一個處理器在總線上輸出此信號時,其餘處理器的請求將被阻塞住,那麼該處理器能夠獨佔共享內存。atom
第二個機制是經過緩存鎖定來保證原子性。在同一時刻,咱們只需保證對某個內存地址的操做是原子性便可,單總線鎖定 把CPU和內存之間的通訊鎖住了,這使得鎖按期間,其餘處理器不能操做其餘內存地址的數據。因此總線鎖定的開銷比較大,目前處理器在某些場合使用緩存鎖定替代總線鎖定來進行優化。線程
所謂的緩存鎖定是指內存區域若是被緩存在處理器的緩存中,而且在Lcok操做期間被鎖定,那麼當他執行鎖操做回寫到內存時,處理器不在總線聲言LOCK#信號,而是修改內部的內存地址。並容許它的緩存一致性機制來保證操做的原子性。由於緩存一致性機制會阻止同時修改由兩個以上處理器緩存的內存區域數據,當其餘處理器回寫已經被鎖定的緩存行的數據時,會使緩存無效。 對象
可是兩種狀況下處理器不能使用緩存鎖定:內存
1.第一種狀況下:當操做的數據不能被緩存在處理器內部,或者操做的數據跨多個緩存行時,處理器會調用總線鎖定。變量
2.有些處理器不支持緩存鎖定
2、java如何實現原子操做
在java中能夠經過鎖和循環CAS的方式來實現原子操做。unsafe類 native的本地方法
從jdk1.5開始,jdk的併發包裏提供了一些類來支持原子操做。如AtomicBoolean(用原子方式更新的boolean值)。這些原子保證類還提供了有用的工具方法,好比原子的方式實現自增1或者自減1.
CAS實現原子操做的三大問題:
1.ABA JDK1.5開始,JDK的atomic包提供了一個類AtomicStampedReference來解決ABA問題。實際是有個版本號的,每次變動更新的時候把版本號加1.
2.自旋時間長開銷大
3.只能保證一個共享變量的原子操做。 JDK1.5開始,AtomicReference類來保證引用對象之間的原子性,就能夠把多個變量放在一個對象裏面進行CAS。