AtomicInteger保證線程安全的全局變量


現有業務場景需要做一個線程間的全局變量,並且實現自增效果。

  初始使用了volatile 來保證count的安全性,如下:

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

public class TestThredd {

    private volatile int count = 0;  
       
    public void increment() {  
        count++;  
    }  
      
    private int getCount() {  
        return count;  
    }  
      
    /** 
     * 這里模擬一個遞增的任務,遞增目標為50000 
     */  
    public static void main(String[] args) throws InterruptedException {  
         final TestThredd counter = new TestThredd();  
        int workCount = 50000;  
        ExecutorService executor = Executors.newFixedThreadPool(10);  
        long start = System.currentTimeMillis();  
        for (int i = 0; i < workCount; i++) {  
            Runnable runnable = new Runnable() {  
                @Override  
                public void run() {  
                    counter.increment();  
                }  
            };  
            executor.execute(runnable);  
        }  
        // 關閉啟動線程,執行未完成的任務  
        executor.shutdown();  
        // 等待所有線程完成任務,完成后才繼續執行下一步  
        executor.awaitTermination(Long.MAX_VALUE, TimeUnit.DAYS);  
        System.out.println("耗時:" + (System.currentTimeMillis() - start) + "ms");  
        System.out.println("執行結果:count=" + counter.getCount());  
    } 
}

執行結果

它的結果不是我們預料的50000 .通常我們需要加上在count++時 加上synchronized關鍵字,保證他的正確性。

如下:

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

public class TestThredd {

    private volatile int count = 0;  
      
    /** 
     * 為了保證數據的准確性,多線程的情況下需要加上synchronized關鍵字
     * 否則會出現出乎預料的結果 這也是線程安全的重要體現 
     */  
    public synchronized void increment() {  
        count++;  
    }  
      
    private int getCount() {  
        return count;  
    }  
      
    /** 
     * 這里模擬一個遞增的任務,遞增目標為50000 
     */  
    public static void main(String[] args) throws InterruptedException {  
        final TestThredd counter = new TestThredd();  
        int workCount = 50000;  
        ExecutorService executor = Executors.newFixedThreadPool(10);  
        long start = System.currentTimeMillis();  
        for (int i = 0; i < workCount; i++) {  
            Runnable runnable = new Runnable() {  
                @Override  
                public void run() {  
                    counter.increment();  
                }  
            };  
            executor.execute(runnable);  
        }  
        // 關閉啟動線程,執行未完成的任務  
        executor.shutdown();  
        // 等待所有線程完成任務,完成后才繼續執行下一步  
        executor.awaitTermination(Long.MAX_VALUE, TimeUnit.DAYS);  
        System.out.println("耗時:" + (System.currentTimeMillis() - start) + "ms");  
        System.out.println("執行結果:count=" + counter.getCount());  
    } 
}

為了保證數據的准確性,多線程的情況下需要加上synchronized關鍵字,否則會出現不安全的操作

如果我們換個方式,用AtomicInteger來替換count++,怎么做呢?

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

public class AtomicCounter {

     private AtomicInteger count = new AtomicInteger(0);  
     
        // 使用AtomicInteger之后,不需要加鎖,也可以實現線程安全。  
        public void increment() {  
            //獲取當前的值並自增  
            count.incrementAndGet();  
        }  
        /** 
         * 獲取當前的值 
         * @return 
         */  
        public int getCount() {  
            return count.get();  
        }  
        //遞減  
        public void deIncrement(){  
            count.decrementAndGet();  
        }  
        
        
        /** 
         * 這里模擬一個遞增的任務,遞增目標為50000 
         */  
        public static void main(String[] args) throws InterruptedException {  
            final AtomicCounter counter = new AtomicCounter();  
            int workCount = 50000;  
            ExecutorService executor = Executors.newFixedThreadPool(10);  
            long start = System.currentTimeMillis();  
            for (int i = 0; i < workCount; i++) {  
                Runnable runnable = new Runnable() {  
                    @Override  
                    public void run() {  
                        counter.increment();  
                    }  
                };  
                executor.execute(runnable);  
            }  
            // 關閉啟動線程,執行未完成的任務  
            executor.shutdown();  
            // 等待所有線程完成任務,完成后才繼續執行下一步  
            executor.awaitTermination(Long.MAX_VALUE, TimeUnit.DAYS);  
            System.out.println("耗時:" + (System.currentTimeMillis() - start) + "ms");  
            System.out.println("執行結果:count=" + counter.getCount());  
        } 
}

AtomicInteger很輕松的實現了線程安全的變量操作

 

Java從JDK 1.5開始提供了java.util.concurrent.atomic包(以下簡稱Atomic包),這個包中的原子操作類提供了一種用法簡單、性能高效、線程安全地更新一個變量的方式。因為變量的類型有很多種,所以在Atomic包里一共提供了13個類,屬於4種類型的原子更新方式,分別是原子更新基本類型、原子更新數組、原子更新引用和原子更新屬性(字段)。Atomic包里的類基本都是使用Unsafe實現的包裝類。

 

使用原子的方式更新基本類型,Atomic包提供了以下3個類。
AtomicBoolean:原子更新布爾類型。
AtomicInteger:原子更新整型。
AtomicLong:原子更新長整型。

 

通過原子的方式更新數組里的某個元素,Atomic包提供了以3類
AtomicIntegerArray:原子更新整型數組里的元素。
AtomicLongArray:原子更新長整型數組里的元素。
AtomicReferenceArray:原子更新引用類型數組里的元素。

 AtomicInteger是一個提供原子操作的Integer類,通過線程安全的方式操作加減。

AtomicInteger是在使用非阻塞算法實現並發控制,在一些高並發程序中非常適合,但並不能每一種場景都適合,不同場景要使用使用不同的數值類。

這是由硬件提供原子操作指令實現的,這里面用到了一種並發技術:CAS。在非激烈競爭的情況下,開銷更小,速度更快。

參考:

http://blog.csdn.net/sunxianghuang/article/details/52277370

http://blog.csdn.net/u012734441/article/details/51619751

http://blog.csdn.net/jan_s/article/details/47025095


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM