在這一部分開(kāi)始討論數(shù)組原子操作和一些其他的原子操作。
AtomicIntegerArray/AtomicLongArray/AtomicReferenceArray的API類似,選擇有代表性的AtomicIntegerArray來(lái)描述這些問(wèn)題。
int get(int i)
獲取位置 i
的當(dāng)前值。很顯然,由于這個(gè)是數(shù)組操作,就有索引越界的問(wèn)題(IndexOutOfBoundsException異常)。
對(duì)于下面的API起始和AtomicInteger是類似的,這種通過(guò)方法、參數(shù)的名稱就能夠得到函數(shù)意義的寫(xiě)法是非常值得稱贊的。在《重構(gòu):改善既有代碼的設(shè)計(jì)》和《代碼整潔之道》中都非常推崇這種做法。
void set(int i, int newValue)
void lazySet(int i, int newValue)
int getAndSet(int i, int newValue)
boolean compareAndSet(int i, int expect, int update)
boolean weakCompareAndSet(int i, int expect, int update)
int getAndIncrement(int i)
int getAndDecrement(int i)
int getAndAdd(int i, int delta)
int incrementAndGet(int i)
int decrementAndGet(int i)
int addAndGet(int i, int delta)
整體來(lái)說(shuō),數(shù)組的原子操作在理解上還是相對(duì)比較容易的,這些API就是有多使用才能體會(huì)到它們的好處,而不僅僅是停留在理論階段。
現(xiàn)在關(guān)注字段的原子更新。
AtomicIntegerFieldUpdater<T>/AtomicLongFieldUpdater<T>/AtomicReferenceFieldUpdater<T,V>是基于反射的原子更新字段的值。
相應(yīng)的API也是非常簡(jiǎn)單的,但是也是有一些約束的。
(1)字段必須是volatile類型的!在后面的章節(jié)中會(huì)詳細(xì)說(shuō)明為什么必須是volatile,volatile到底是個(gè)什么東西。
(2)字段的描述類型(修飾符public/protected/default/private)是與調(diào)用者與操作對(duì)象字段的關(guān)系一致。也就是說(shuō)調(diào)用者能夠直接操作對(duì)象字段,那么就可以反射進(jìn)行原子操作。但是對(duì)于父類的字段,子類是不能直接操作的,盡管子類可以訪問(wèn)父類的字段。
(3)只能是實(shí)例變量,不能是類變量,也就是說(shuō)不能加static關(guān)鍵字。
(4)只能是可修改變量,不能使final變量,因?yàn)閒inal的語(yǔ)義就是不可修改。實(shí)際上final的語(yǔ)義和volatile是有沖突的,這兩個(gè)關(guān)鍵字不能同時(shí)存在。
(5)對(duì)于AtomicIntegerFieldUpdater和AtomicLongFieldUpdater只能修改int/long類型的字段,不能修改其包裝類型(Integer/Long)。如果要修改包裝類型就需要使用AtomicReferenceFieldUpdater。
在下面的例子中描述了操作的方法。
package xylz.study.concurrency.atomic;

import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;


public class AtomicIntegerFieldUpdaterDemo
{


class DemoData
{
public volatile int value1 = 1;
volatile int value2 = 2;
protected volatile int value3 = 3;
private volatile int value4 = 4;
}

AtomicIntegerFieldUpdater<DemoData> getUpdater(String fieldName)
{
return AtomicIntegerFieldUpdater.newUpdater(DemoData.class, fieldName);
}

void doit()
{
DemoData data = new DemoData();
System.out.println("1 ==> "+getUpdater("value1").getAndSet(data, 10));
System.out.println("3 ==> "+getUpdater("value2").incrementAndGet(data));
System.out.println("2 ==> "+getUpdater("value3").decrementAndGet(data));
System.out.println("true ==> "+getUpdater("value4").compareAndSet(data, 4, 5));
}

public static void main(String[] args)
{
AtomicIntegerFieldUpdaterDemo demo = new AtomicIntegerFieldUpdaterDemo();
demo.doit();
}
}


在上面的例子中DemoData的字段value3/value4對(duì)于AtomicIntegerFieldUpdaterDemo類是不可見(jiàn)的,因此通過(guò)反射是不能直接修改其值的。
AtomicMarkableReference類描述的一個(gè)<Object,Boolean>的對(duì),可以原子的修改Object或者Boolean的值,這種數(shù)據(jù)結(jié)構(gòu)在一些緩存或者狀態(tài)描述中比較有用。這種結(jié)構(gòu)在單個(gè)或者同時(shí)修改Object/Boolean的時(shí)候能夠有效的提高吞吐量。
AtomicStampedReference類維護(hù)帶有整數(shù)“標(biāo)志”的對(duì)象引用,可以用原子方式對(duì)其進(jìn)行更新。對(duì)比AtomicMarkableReference類的<Object,Boolean>,AtomicStampedReference維護(hù)的是一種類似<Object,int>的數(shù)據(jù)結(jié)構(gòu),其實(shí)就是對(duì)對(duì)象(引用)的一個(gè)并發(fā)計(jì)數(shù)。但是與AtomicInteger不同的是,此數(shù)據(jù)結(jié)構(gòu)可以攜帶一個(gè)對(duì)象引用(Object),并且能夠?qū)Υ藢?duì)象和計(jì)數(shù)同時(shí)進(jìn)行原子操作。
在后面的章節(jié)中會(huì)提到“ABA問(wèn)題”,而AtomicMarkableReference/AtomicStampedReference在解決“ABA問(wèn)題”上很有用。
原子操作的使用大概就是這么多,大體來(lái)說(shuō)還算是比較清晰的,在下一個(gè)章節(jié)中,將對(duì)象原子操作進(jìn)行總結(jié),重點(diǎn)介紹下原子操作的原理和設(shè)計(jì)思想。
©2009-2014 IMXYLZ
|求賢若渴