java 原子操作深入淺出

Java中的原子操作包括:
1)除long和double之外的基本類型的賦值操作
2)所有引用reference的賦值操作
3)java.concurrent.Atomic.* 包中所有類的一切操作

count++不是原子操作,是3個原子操作組合
1.讀取主存中的count值,賦值給一個局部成員變量tmp
2.tmp+1
3.將tmp賦值給count
可能會出現線程1運行到第2步的時候,tmp值爲1;這時CPU調度切換到線程2執行完畢,count值爲1;切換到線程1,繼續執行第3步,count被賦值爲1------------結果就是兩個線程執行完畢,count的值只加了1;

 

JDK1.5之後的java.util.concurrent.atomic包裏,多了一批原子處理類。AtomicBoolean、AtomicInteger、AtomicLong、AtomicReference。主要用於在高併發環境下的高效程序處理,來幫助我們簡化同步處理.

AtomicInteger:

AtomicInteger,一個提供原子操作的Integer的類。

在Java語言中,++i和i++操作並不是線程安全的,在使用的時候,不可避免的會用到synchronized關鍵字。

而AtomicInteger則通過一種線程安全的加減操作接口。

我們先來看看AtomicInteger給我們提供了什麼接口:

public final int get() //獲取當前的值
public final int getAndSet(int newValue)//獲取當前的值,並設置新的值
public final int getAndIncrement()//獲取當前的值,並自增
public final int getAndDecrement() //獲取當前的值,並自減
public final int getAndAdd(int delta) //獲取當前的值,並加上預期的值

下面通過兩個簡單的例子來看一下 AtomicInteger 的優勢在哪:

普通線程同步:

class Test2 {
        private volatile int count = 0;

        public synchronized void increment() {
                  count++; //若要線程安全執行count++,需要加鎖
        }

        public int getCount() {
                  return count;
        }
}

使用AtomicInteger:

class Test2 {
        private AtomicInteger count = new AtomicInteger();

        public void increment() {
                  count.incrementAndGet();
        }
   //使用AtomicInteger之後,不需要加鎖,也可以實現線程安全。
       public int getCount() {
                return count.get();
        }
}

從上面的例子中我們可以看出:使用AtomicInteger是非常的安全的.而且因爲AtomicInteger由硬件提供原子操作指令實現的。在非激烈競爭的情況下,開銷更小,速度更快。

我們來看看AtomicInteger是如何使用非阻塞算法來實現併發控制的:
AtomicInteger的關鍵域只有以下3個:

// setup to use Unsafe.compareAndSwapInt for updates
private static final Unsafe unsafe = Unsafe.getUnsafe();
private static final long valueOffset;
static {    
         try {        
                valueOffset = unsafe.objectFieldOffset (AtomicInteger.class.getDeclaredField("value"));   
        } catch (Exception ex) { 
               throw new Error(ex); 
        }
    }
private volatile int value;

這裏, unsafe是java提供的獲得對對象內存地址訪問的類,它的作用就是在更新操作時提供“比較並替換”的作用。實際上就是AtomicInteger中的一個工具。
valueOffset是用來記錄value本身在內存的便宜地址的,這個記錄,也主要是爲了在更新操作在內存中找到value的位置,方便比較。
注意:value是用來存儲整數的時間變量,這裏被聲明爲volatile,就是爲了保證在更新操作時,當前線程可以拿到value最新的值(併發環境下,value可能已經被其他線程更新了)。
這裏,我們以自增的代碼爲例,可以看到這個併發控制的核心算法:

/**
*Atomically increment sbyone the current value.
*
*@return the updated value
*/
public final int incrementAndGet(){
for(;;){
//這裏可以拿到value的最新值
int current=get();
int next=current+1;
if(compareAndSet(current,next))
return next;
}
}

public final boolean compareAndSet(intexpect,intupdate){
//使用unsafe的native方法,實現高效的硬件級別CAS
        return unsafe.compareAndSwapInt(this,valueOffset,expect,update);
}

優點總結:
最大的好處就是可以避免多線程的優先級倒置和死鎖情況的發生,提升在高併發處理下的性能。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章