并發(fā)中處理數(shù)據(jù)很容易導(dǎo)致數(shù)據(jù)的不一致性撵彻,如前一個線程改了(未完)起胰,后一個線程來讀,對于簡單數(shù)據(jù)采用同步性能又不太好。
原子性布爾 AtomicBoolean
AtomicBoolean 類為我們提供了一個可以用原子方式進(jìn)行讀和寫的布爾值总滩,它還擁有一些先進(jìn)的原子性操作男摧,比如 compareAndSet()索绪。AtomicBoolean 類位于 java.util.concurrent.atomic 包契吉,完整類名是為 java.util.concurrent.atomic.AtomicBoolean。本小節(jié)描述的 AtomicBoolean 是 Java 8 版本里的屑迂,而不是它第一次被引入的 Java 5 版本浸策。
AtomicBoolean 背后的設(shè)計理念在我的《Java 并發(fā)指南》主題的《 比較和交換》小節(jié)有解釋。
創(chuàng)建一個 AtomicBoolean
你可以這樣創(chuàng)建一個 AtomicBoolean:
AtomicBoolean atomicBoolean = new AtomicBoolean();
以上示例新建了一個默認(rèn)值為 false 的 AtomicBoolean惹盼。
如果你想要為 AtomicBoolean 實(shí)例設(shè)置一個顯式的初始值的榛,那么你可以將初始值傳給 AtomicBoolean 的構(gòu)造子:
AtomicBoolean atomicBoolean = new AtomicBoolean(true);
獲取 AtomicBoolean 的值
你可以通過使用 get() 方法來獲取一個 AtomicBoolean 的值。示例如下:
AtomicBoolean atomicBoolean = new AtomicBoolean(true);
boolean value = atomicBoolean.get();
以上代碼執(zhí)行后 value 變量的值將為 true逻锐。
設(shè)置 AtomicBoolean 的值
你可以通過使用 set() 方法來設(shè)置一個 AtomicBoolean 的值夫晌。示例如下:
AtomicBoolean atomicBoolean = new AtomicBoolean(true);
atomicBoolean.set(false);
以上代碼執(zhí)行后 AtomicBoolean 的值為 false。
交換 AtomicBoolean 的值
你可以通過 getAndSet() 方法來交換一個 AtomicBoolean 實(shí)例的值昧诱。getAndSet() 方法將返回 AtomicBoolean 當(dāng)前的值晓淀,并將為 AtomicBoolean 設(shè)置一個新值。示例如下:
AtomicBoolean atomicBoolean = new AtomicBoolean(true);
boolean oldValue = atomicBoolean.getAndSet(false);
以上代碼執(zhí)行后 oldValue 變量的值為 true盏档,atomicBoolean 實(shí)例將持有 false 值凶掰。代碼成功將 AtomicBoolean 當(dāng)前值 ture 交換為 false。
比較并設(shè)置 AtomicBoolean 的值
compareAndSet() 方法允許你對 AtomicBoolean 的當(dāng)前值與一個期望值進(jìn)行比較蜈亩,如果當(dāng)前值等于期望值的話懦窘,將會對 AtomicBoolean 設(shè)定一個新值。compareAndSet() 方法是原子性的稚配,因此在同一時間之內(nèi)有單個線程執(zhí)行它畅涂。因此 compareAndSet() 方法可被用于一些類似于鎖的同步的簡單實(shí)現(xiàn)。
以下是一個 compareAndSet() 示例:
AtomicBoolean atomicBoolean = new AtomicBoolean(true);
boolean expectedValue = true;
boolean newValue = false;
boolean wasNewValueSet = atomicBoolean.compareAndSet(
expectedValue, newValue);
本示例對 AtomicBoolean 的當(dāng)前值與 true 值進(jìn)行比較道川,如果相等午衰,將 AtomicBoolean 的值更新為 false立宜。
原子性整型 AtomicInteger
AtomicInteger 類為我們提供了一個可以進(jìn)行原子性讀和寫操作的 int 變量,它還包含一系列先進(jìn)的原子性操作臊岸,比如 compareAndSet()橙数。AtomicInteger 類位于 java.util.concurrent.atomic 包,因此其完整類名為 java.util.concurrent.atomic.AtomicInteger帅戒。本小節(jié)描述的 AtomicInteger 是 Java 8 版本里的灯帮,而不是它第一次被引入的 Java 5 版本。
AtomicInteger 背后的設(shè)計理念在我的《Java 并發(fā)指南》主題的《 比較和交換》小節(jié)有解釋逻住。
創(chuàng)建一個 AtomicInteger
創(chuàng)建一個 AtomicInteger 示例如下:
AtomicInteger atomicInteger = new AtomicInteger();
本示例將創(chuàng)建一個初始值為 0 的 AtomicInteger钟哥。
如果你想要創(chuàng)建一個給定初始值的 AtomicInteger,你可以這樣:
AtomicInteger atomicInteger = new AtomicInteger(123);
本示例將 123 作為參數(shù)傳給 AtomicInteger 的構(gòu)造子鄙信,它將設(shè)置 AtomicInteger 實(shí)例的初始值為 123瞪醋。
獲取 AtomicInteger 的值
你可以使用 get() 方法獲取 AtomicInteger 實(shí)例的值忿晕。示例如下:
AtomicInteger atomicInteger = new AtomicInteger(123);
int theValue = atomicInteger.get();
設(shè)置 AtomicInteger 的值
你可以通過 set() 方法對 AtomicInteger 的值進(jìn)行重新設(shè)置装诡。以下是 AtomicInteger.set() 示例:
AtomicInteger atomicInteger = new AtomicInteger(123);
atomicInteger.set(234);
以上示例創(chuàng)建了一個初始值為 123 的 AtomicInteger,而在第二行將其值更新為 234践盼。
比較并設(shè)置 AtomicInteger 的值
AtomicInteger 類也通過了一個原子性的 compareAndSet() 方法鸦采。這一方法將 AtomicInteger 實(shí)例的當(dāng)前值與期望值進(jìn)行比較,如果二者相等咕幻,為 AtomicInteger 實(shí)例設(shè)置一個新值渔伯。AtomicInteger.compareAndSet() 代碼示例:
AtomicInteger atomicInteger = new AtomicInteger(123);
int expectedValue = 123;
int newValue = 234;
atomicInteger.compareAndSet(expectedValue, newValue);
本示例首先新建一個初始值為 123 的 AtomicInteger 實(shí)例。然后將 AtomicInteger 與期望值 123 進(jìn)行比較肄程,如果相等锣吼,將 AtomicInteger 的值更新為 234。
增加 AtomicInteger 值
AtomicInteger 類包含有一些方法蓝厌,通過它們你可以增加 AtomicInteger 的值玄叠,并獲取其值。這些方法如下:
- addAndGet()
- getAndAdd()
- getAndIncrement()
- incrementAndGet()
第一個 addAndGet() 方法給 AtomicInteger 增加了一個值拓提,然后返回增加后的值读恃。getAndAdd() 方法為 AtomicInteger 增加了一個值,但返回的是增加以前的 AtomicInteger 的值代态。具體使用哪一個取決于你的應(yīng)用場景寺惫。以下是這兩種方法的示例:
AtomicInteger atomicInteger = new AtomicInteger();
System.out.println(atomicInteger.getAndAdd(10));
System.out.println(atomicInteger.addAndGet(10));
本示例將打印出 0 和 20。例子中蹦疑,第二行拿到的是加 10 之前的 AtomicInteger 的值西雀。加 10 之前的值是 0。第三行將 AtomicInteger 的值再加 10歉摧,并返回加操作之后的值蒋搜。該值現(xiàn)在是為 20篡撵。
你當(dāng)然也可以使用這倆方法為 AtomicInteger 添加負(fù)值。結(jié)果實(shí)際是一個減法操作豆挽。
getAndIncrement() 和 incrementAndGet() 方法類似于 getAndAdd() 和 addAndGet()育谬,但每次只將 AtomicInteger 的值加 1。
減小 AtomicInteger 的值
AtomicInteger 類還提供了一些減小 AtomicInteger 的值的原子性方法帮哈。這些方法是:
- decrementAndGet()
- getAndDecrement()
decrementAndGet() 將 AtomicInteger 的值減一膛檀,并返回減一后的值。getAndDecrement() 也將 AtomicInteger 的值減一娘侍,但它返回的是減一之前的值咖刃。
原子性長整型 AtomicLong
AtomicLong 類為我們提供了一個可以進(jìn)行原子性讀和寫操作的 long 變量,它還包含一系列先進(jìn)的原子性操作憾筏,比如 compareAndSet()AtomicLong 類位于 java.util.concurrent.atomic 包嚎杨,因此其完整類名為 java.util.concurrent.atomic.AtomicLong。本小節(jié)描述的 AtomicLong 是 Java 8 版本里的氧腰,而不是它第一次被引入的 Java 5 版本枫浙。
AtomicLong 背后的設(shè)計理念在我的《Java 并發(fā)指南》主題的《 比較和交換》小節(jié)有解釋。
創(chuàng)建一個 AtomicLong
創(chuàng)建一個 AtomicLong 如下:
AtomicLong atomicLong = new AtomicLong();
將創(chuàng)建一個初始值為 0 的 AtomicLong古拴。
如果你想創(chuàng)建一個指定初始值的 AtomicLong箩帚,可以:
AtomicLong atomicLong = new AtomicLong(123);
本示例將 123 作為參數(shù)傳遞給 AtomicLong 的構(gòu)造子,后者將 AtomicLong 實(shí)例的初始值設(shè)置為 123黄痪。
獲取 AtomicLong 的值
你可以通過 get() 方法獲取 AtomicLong 的值紧帕。AtomicLong.get() 示例:
AtomicLong atomicLong = new AtomicLong(123);
long theValue = atomicLong.get();
設(shè)置 AtomicLong 的值
你可以通過 set() 方法設(shè)置 AtomicLong 實(shí)例的值。一個 AtomicLong.set() 的示例:
AtomicLong atomicLong = new AtomicLong(123);
atomicLong.set(234);
本示例新建了一個初始值為 123 的 AtomicLong桅打,第二行將其值設(shè)置為 234是嗜。
比較并設(shè)置 AtomicLong 的值
AtomicLong 類也有一個原子性的 compareAndSet() 方法。這一方法將 AtomicLong 實(shí)例的當(dāng)前值與一個期望值進(jìn)行比較挺尾,如果兩種相等鹅搪,為 AtomicLong 實(shí)例設(shè)置一個新值。AtomicLong.compareAndSet() 使用示例:
AtomicLong atomicLong = new AtomicLong(123);
long expectedValue = 123;
long newValue = 234;
atomicLong.compareAndSet(expectedValue, newValue);
本示例新建了一個初始值為 123 的 AtomicLong潦嘶。然后將 AtomicLong 的當(dāng)前值與期望值 123 進(jìn)行比較涩嚣,如果相等的話,AtomicLong 的新值將變?yōu)?234掂僵。
增加 AtomicLong 值
AtomicLong 具備一些能夠增加 AtomicLong 的值并返回自身值的方法航厚。這些方法如下:
- addAndGet()
- getAndAdd()
- getAndIncrement()
- incrementAndGet()
第一個方法 addAndGet() 將 AtomicLong 的值加一個數(shù)字,并返回增加后的值锰蓬。第二個方法 getAndAdd() 也將 AtomicLong 的值加一個數(shù)字幔睬,但返回的是增加前的 AtomicLong 的值。具體使用哪一個取決于你自己的場景芹扭。示例如下:
AtomicLong atomicLong = new AtomicLong();
System.out.println(atomicLong.getAndAdd(10));
System.out.println(atomicLong.addAndGet(10));
本示例將打印出 0 和 20麻顶。例子中赦抖,第二行拿到的是加 10 之前的 AtomicLong 的值。加 10 之前的值是 0辅肾。第三行將 AtomicLong 的值再加 10队萤,并返回加操作之后的值。該值現(xiàn)在是為 20矫钓。
你當(dāng)然也可以使用這倆方法為 AtomicLong 添加負(fù)值要尔。結(jié)果實(shí)際是一個減法操作。
getAndIncrement() 和 incrementAndGet() 方法類似于 getAndAdd() 和 addAndGet()新娜,但每次只將 AtomicLong 的值加 1赵辕。
減小 AtomicLong 的值
AtomicLong 類還提供了一些減小 AtomicLong 的值的原子性方法。這些方法是:
- decrementAndGet()
- getAndDecrement()
decrementAndGet() 將 AtomicLong 的值減一概龄,并返回減一后的值还惠。getAndDecrement() 也將 AtomicLong 的值減一,但它返回的是減一之前的值私杜。
原子性引用型 AtomicReference
AtomicReference 提供了一個可以被原子性讀和寫的對象引用變量蚕键。原子性的意思是多個想要改變同一個 AtomicReference 的線程不會導(dǎo)致 AtomicReference 處于不一致的狀態(tài)。AtomicReference 還有一個 compareAndSet() 方法歪今,通過它你可以將當(dāng)前引用于一個期望值(引用)進(jìn)行比較嚎幸,如果相等颜矿,在該 AtomicReference 對象內(nèi)部設(shè)置一個新的引用寄猩。
創(chuàng)建一個 AtomicReference
創(chuàng)建 AtomicReference 如下:
AtomicReference atomicReference = new AtomicReference();
如果你需要使用一個指定引用創(chuàng)建 AtomicReference,可以:
String initialReference = "the initially referenced string";
AtomicReference atomicReference = new AtomicReference(initialReference);
創(chuàng)建泛型 AtomicReference
你可以使用 Java 泛型來創(chuàng)建一個泛型 AtomicReference骑疆。示例:
AtomicReference<String> atomicStringReference =
new AtomicReference<String>();
你也可以為泛型 AtomicReference 設(shè)置一個初始值田篇。示例:
String initialReference = "the initially referenced string";
AtomicReference<String> atomicStringReference =
new AtomicReference<String>(initialReference);
獲取 AtomicReference 引用
你可以通過 AtomicReference 的 get() 方法來獲取保存在 AtomicReference 里的引用。如果你的 AtomicReference 是非泛型的箍铭,get() 方法將返回一個 Object 類型的引用泊柬。如果是泛型化的,get() 將返回你創(chuàng)建 AtomicReference 時聲明的那個類型诈火。
先來看一個非泛型的 AtomicReference get() 示例:
AtomicReference atomicReference = new AtomicReference("first value referenced");
String reference = (String) atomicReference.get();
注意如何對 get() 方法返回的引用強(qiáng)制轉(zhuǎn)換為 String兽赁。
泛型化的 AtomicReference 示例:
AtomicReference<String> atomicReference =
new AtomicReference<String>("first value referenced");
String reference = atomicReference.get();
編譯器知道了引用的類型,所以我們無需再對 get() 返回的引用進(jìn)行強(qiáng)制轉(zhuǎn)換了冷守。
設(shè)置 AtomicReference 引用
你可以使用 get() 方法對 AtomicReference 里邊保存的引用進(jìn)行設(shè)置刀崖。如果你定義的是一個非泛型 AtomicReference,set() 將會以一個 Object 引用作為參數(shù)拍摇。如果是泛型化的 AtomicReference亮钦,set() 方法將只接受你定義給的類型。
AtomicReference set() 示例:
AtomicReference atomicReference =
new AtomicReference();
atomicReference.set("New object referenced");
這個看起來非泛型和泛型化的沒啥區(qū)別充活。真正的區(qū)別在于編譯器將對你能夠設(shè)置給一個泛型化的 AtomicReference 參數(shù)類型進(jìn)行限制蜂莉。
比較并設(shè)置 AtomicReference 引用
AtomicReference 類具備了一個很有用的方法:compareAndSet()蜡娶。compareAndSet() 可以將保存在 AtomicReference 里的引用于一個期望引用進(jìn)行比較,如果兩個引用是一樣的(并非 equals() 的相等映穗,而是 == 的一樣)窖张,將會給 AtomicReference 實(shí)例設(shè)置一個新的引用。
如果 compareAndSet() 為 AtomicReference 設(shè)置了一個新的引用蚁滋,compareAndSet() 將返回 true荤堪。否則 compareAndSet() 返回 false。
AtomicReference compareAndSet() 示例:
String initialReference = "initial value referenced";
AtomicReference<String> atomicStringReference =
new AtomicReference<String>(initialReference);
String newReference = "new value referenced";
boolean exchanged = atomicStringReference.compareAndSet(initialReference, newReference);
System.out.println("exchanged: " + exchanged);
exchanged = atomicStringReference.compareAndSet(initialReference, newReference);
System.out.println("exchanged: " + exchanged);
本示例創(chuàng)建了一個帶有一個初始引用的泛型化的 AtomicReference枢赔。之后兩次調(diào)用 comparesAndSet()來對存儲值和期望值進(jìn)行對比澄阳,如果二者一致,為 AtomicReference 設(shè)置一個新的引用踏拜。第一次比較碎赢,存儲的引用(initialReference)和期望的引用(initialReference)一致,所以一個新的引用(newReference)被設(shè)置給 AtomicReference速梗,compareAndSet() 方法返回 true肮塞。第二次比較時,存儲的引用(newReference)和期望的引用(initialReference)不一致姻锁,因此新的引用沒有被設(shè)置給 AtomicReference枕赵,compareAndSet() 方法返回 false。
原文鏈接: http://tutorials.jenkov.com/java-util-concurrent/index.html位隶。