Java針對多執行緒下的數值安全計數器設計了一些類別,這些類別叫做原子類別,其中一部分如下:
java.util.concurrent.atomic.AtomicBoolean;java.util.concurrent.atomic.AtomicInteger;java.util.concurrent.atomic.AtomicLong;java.util.concurrent.atomic.AtomicReference;
下面是一個對比AtomicInteger 與普通int 值在多執行緒下的遞增測試,使用的是junit4;
完整程式碼:
package test.java;import java.util.concurrent.CountDownLatch;import java.util.concurrent.atomic.AtomicInteger;import org.junit.Assert;import org.junit.Before;import org.junit.Test;/**** *測試AtomicInteger與普通int值在多執行緒下的遞增操作*/public class TestAtomic { //原子Integer遞增物件public static AtomicInteger counter_integer;// = new AtomicInteger(0); // 一個int類型的變數public static int count_int = 0; @Before public void setUp() { // 所有測試開始前執行初始設定工作counter_integer = new AtomicInteger(0); } @Test public void testAtomic() throws InterruptedException { // 建立的執行緒數int threadCount = 100; // 其他附屬執行緒內部迴圈多少次int loopCount = 10000600; // 控製附屬執行緒的輔助物件;(其他await的執行緒先等著主執行緒開始) CountDownLatch latch_1 = new CountDownLatch(1); // 控制主執行緒的輔助物件;(主執行緒等著所有附屬執行緒都運行完畢再繼續) CountDownLatch latch_n = new CountDownLatch(threadCount); // 建立並啟動其他附屬執行緒for (int i = 0; i < threadCount; i++) { Thread thread = new AtomicIntegerThread(latch_1, latch_n, loopCount); threadCount); } long startNano = System.nanoTime(); //讓其他等待的執行緒統一開始latch_1.countDown(); // 等待其他執行緒執行完latch_n.await(); // long endNano = System.nanoTime(); int sum = counter_integer.get(); // Assert. assertEquals("sum 不等於threadCount * loopCount,測試失敗", sum, threadCount * loopCount); System.out.println("--------testAtomic(); 預期兩者相等------------"); System.out.println("耗時: " + ((endNano - startNano) / (1000 * 1000)) + "ms"); System.out.println("threadCount = " + (threadCount) + ";"); System.out.println("loopCount = " + (loopCount) + ";"); System.out.println("sum = " + (sum) + ";"); } @Test public void testIntAdd() throws InterruptedException { // 建立的執行緒數int threadCount = 100; // 其他附屬執行緒內部迴圈幾次int loopCount = 10000600; // 控製附屬執行緒的輔助物件;(其他await的執行緒先等著主執行緒喊開始) CountDownLatch latch_1 = new CountDownLatch(1); // 控制主執行緒的輔助物件;(主執行緒等著所有附屬執行緒都執行完畢再繼續) CountDownLatch latch_n = new CountDownLatch(threadCount); // 建立並啟動其他附屬執行緒forfor (int i = 0; i < threadCount; i++) { Thread thread = new IntegerThread(latch_1, latch_n, loopCount); thread.start(); } long startNano = System.nanoTime(); // 讓其他等待的執行緒統一開始latch_1.countDown(); // 等待其他執行緒執行完latch_n.await(); / / 長 endNano = System.nanoTime(); int sum = count_int; // Assert.assertNotEquals( "sum 等於threadCount * loopCount,testIntAdd()測試失敗", sum, threadCount * loopCount); System.out.println("-------testIntAdd(); 預期兩者不相等---------") ; System.out.println("耗時: " + ((endNano - startNano) / (1000*1000))+ "ms"); System.out.println("threadCount = " + (threadCount) + ";"); System.out.println("loopCount = " + (loopCount) + ";"); System.out.println("sum = " + (sum) + ";"); } // 執行緒class AtomicIntegerThread extends Thread { private CountDownLatch latch = null; private CountDownLatch latchdown = null; private int loopCount; public AtomicIntegerThread(CountDownLatch latch, CountDownLatch latchdown, int loopCount) { this.latch = latch; this.latchdown = latchdown; this.loopCount = loopCount; } @Override public void run() { // 等待信號同步try { this.latch. } @Override public void run() { // 等待訊號同步try { this.latch. await(); } catch (InterruptedException e) { e.printStackTrace(); } // for (int i = 0; i < loopCount; i++) { counter_integer.getAndIncrement(); } // 通知遞減1次latchdown.countDown(); } } // 執行緒class IntegerThread extends Thread { private CountDownLatch latch = null ; private CountDownLatch latchdown = null; private int loopCount; public IntegerThread(CountDownLatch latch, CountDownLatch latchdown, int loopCount) { this.latch = latch; this.latchdown = latchdown; this.loopCount = loopCount; } @Override public void run() { // 等待訊號同步try { this.this. await(); } catch (InterruptedException e) { e.printStackTrace(); } // for (int i = 0; i < loopCount; i++) { count_int++; } // 通知遞減1次latchdown.countDown(); } }}
普通PC機上的執行結果類似如下:
--------------testAtomic(); 預期兩者相等-------------------耗時: 85366msthreadCount = 100;loopCount = 10000600;sum = 1000060000;--------------testIntAdd(); 預期兩者不相等-------------------耗時: 1406msthreadCount = 100;loopCount = 10000600;sum = 119428988;
從中可以看出, AtomicInteger操作與int操作的效率大致相差在50-80倍上下,當然,int很不消耗時間,這個對比只是提供一個參考。
如果確定是單執行緒執行,那應該使用int; 而int在多執行緒下的操作執行的效率還是蠻高的, 10億次只花了1.5秒鐘;
(假設CPU是2GHZ,雙核心4線程,理論最大8GHZ,則每秒理論上有80億個時鐘週期,
10億次Java的int增加消耗了1.5秒,即120億次運算, 算下來每次循環消耗CPU週期12個;
個人覺得效率不錯, C 語言也應該需要4個以上的時脈週期(判斷,執行內部程式碼,自增判斷,跳轉)
前提是: JVM和CPU沒有進行激進最佳化.
)
而AtomicInteger 效率其實也不低,10億次消耗了80秒, 那100萬次大約也就是千分之一,80毫秒的樣子.