JDK 原子操作類詳解(AtomicInteger、AtomicIntegerArray等)
阿新 • • 發佈:2019-01-08
當程式更新一個變數時,如果多執行緒同時更新這個變數,可能得到期望之外的值,比如變數i=1,A執行緒更新i+1,B執行緒也更新i+1,經過兩個執行緒操作之後可能i不等於3,而是等於2。因為A和B執行緒在更新變數i的時候拿到的i都是1,這就是執行緒不安全的更新操作,通常我們會使用synchronized來解決這個問題,synchronized會保證多執行緒不會同時更新變數i。
- import java.util.concurrent.CountDownLatch;
- publicclass UnSafeAdd {
- privatestaticint threadCount=10;
- private
- privatestaticint count=0;
- privatestaticclass Counter implements Runnable{
- @Override
- publicvoid run() {
- for(int i=0;i<1000;i++){
- count++;//非原子操作
- }
- countDown.countDown();
- }
- }
- publicstaticvoid main(String[] args) throws InterruptedException {
- Thread[] threads=new Thread[threadCount];
- for(int i=0;i<threadCount;i++){
- threads[i]=new Thread(new Counter());
- }
- for(int i=0;i<threadCount;i++){
- threads[i].start();;
- }
- countDown.await();
- System.out.println(count);
- }
8968
- import java.util.concurrent.CountDownLatch;
- publicclass SafeAddWithSyn {
- privatestaticint threadCount=10;
- privatestatic CountDownLatch countDown=new CountDownLatch(threadCount);
- privatestaticint count=0;
- synchronizedprivatestaticvoid addCount(){//同步方法
- count++;
- }
- privatestaticclass Counter implements Runnable{
- @Override
- publicvoid run() {
- for(int i=0;i<1000;i++){
- addCount();
- }
- countDown.countDown();
- }
- }
- publicstaticvoid main(String[] args) throws InterruptedException {
- Thread[] threads=new Thread[threadCount];
- for(int i=0;i<threadCount;i++){
- threads[i]=new Thread(new Counter());
- }
- for(int i=0;i<threadCount;i++){
- threads[i].start();;
- }
- countDown.await();
- System.out.println(count);
- }
- }
10000
而Java從JDK 1.5開始提供了java.util.concurrent.atomic包(以下簡稱Atomic包),這個包中的原子操作類提供了一種用法簡單、效能高效、執行緒安全地更新一個變數的方式。因為變數的型別有很多種,所以在Atomic包裡一共提供了13個類,屬於4種類型的原子更新方式,分別是原子更新基本型別、原子更新陣列、原子更新引用和原子更新屬性(欄位)。Atomic包裡的類基本都是使用Unsafe實現的包裝類。
- import java.util.concurrent.CountDownLatch;
- import java.util.concurrent.atomic.AtomicInteger;
- publicclass SafeAddWithAtomicInteger {
- privatestaticint threadCount=10;
- privatestatic CountDownLatch countDown=new CountDownLatch(threadCount);
- privatestatic AtomicInteger count=new AtomicInteger(0);//原子操作類
- privatestaticclass Counter implements Runnable{
- @Override
- publicvoid run() {
- for(int i=0;i<1000;i++){
- count.addAndGet(1);
- }
- countDown.countDown();
- }
- }
- publicstaticvoid main(String[] args) throws InterruptedException {
- Thread[] threads=new Thread[threadCount];
- for(int i=0;i<threadCount;i++){
- threads[i]=new Thread(new Counter());
- }
- for(int i=0;i<threadCount;i++){
- threads[i].start();;
- }
- countDown.await();
- System.out.println(count.get());
- }
- }
10000
原子更新基本型別
使用原子的方式更新基本型別,Atomic包提供了以下3個類。
AtomicBoolean:原子更新布林型別。
AtomicInteger:原子更新整型。
AtomicLong:原子更新長整型。
以上3個類提供的方法幾乎一模一樣,所以本節僅以AtomicInteger為例進行講解,AtomicInteger的原始碼如下:
- publicclass AtomicInteger extends Number implements java.io.Serializable {
- privatestaticfinallong serialVersionUID = 6214790243416807050L;
- // setup to use Unsafe.compareAndSwapInt for updates 使用Unsafe類的CAS操作實現更新
- privatestaticfinal Unsafe unsafe = Unsafe.getUnsafe();
- privatestaticfinallong valueOffset;
- ......
- //volatile保證可見性
- privatevolatileint value;
- //構造器