原子類之AtomicLong
java線程中的操作,需要滿足原子性、可見性等原則,比如i++這樣的操作不具備原子性,
A線程讀取了i,另一個線程執行i++,A線程再執行i++就會引發線程安全問題
推薦學習的AtomicInteger和AtomicLong部落格
一個非原子性的自加引發的安全例子
下面的例子執行1000個線程,有意思的還Long自加比Interger更容易發現結果是比1000小。
package com.java.javabase.thread.base.concurrent.atomic;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
@Slf4j
public class AtomicLongtest {
public static void main(String[] args) {
AtomicLongtest test =new AtomicLongtest();
Count count =test.new Count();
ExecutorService service = Executors.newCachedThreadPool();
for(int i=0;i<1000;i++){
service.execute(()->count.increace());
}
service.shutdown();
try {
service.awaitTermination(1, TimeUnit.DAYS);
} catch (InterruptedException e) {
e.printStackTrace();
}
log.info("End count :{}",count.getCount());
}
@Data
class Count{
private Long count=0L;
public void increace(){
log.info("count {}",count++);
}
}
}
通過syncronized方法
通過syncronized方法使得自加操作安全
使用AtomicLong滿足原子性
使用AtomicLong滿足原子性主要是實作了CAS
比較并交換(compare and swap, CAS),是原子操作的一種,可用于在多線程程式設計中實作不被打斷的資料交換操作,進而避免多線程同時改寫某一資料時由于執行順序不确定性以及中斷的不可預知性産生的資料不一緻問題。 該操作通過将記憶體中的值與指定資料進行比較,當數值一樣時将記憶體中的資料替換為新的值。
使用使用AtomicLong,1000個線程執行之後傳回的結果是1000,保證了結果的正确
package com.java.javabase.thread.base.concurrent.atomic;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
@Slf4j
public class AtomicLongTest2 {
public static void main(String[] args) {
AtomicLongTest2 test =new AtomicLongTest2();
Count count =test.new Count();
ExecutorService service = Executors.newCachedThreadPool();
for(int i=0;i<1000;i++){
service.execute(()->count.increace());
}
service.shutdown();
try {
service.awaitTermination(1, TimeUnit.DAYS);
} catch (InterruptedException e) {
e.printStackTrace();
}
log.info("End count :{}",count.getCount());
}
@Data
class Count{
private AtomicLong count=new AtomicLong(0);
public void increace(){
log.info("count {}",count.incrementAndGet());
}
}
}
AtomicLong的ABA問題
CAS有一個問題是ABA問題:
1.ABC三個線程
2.count=10,這時AB線程的記憶體值和預期值都是10
3.B線程把count修改100成功後,記憶體值是100
4.A線程又把count設定為10
5.這個時候記憶體值和預期值都是10
6.c線程是不知道A和B對count做了什麼操作的