三種遞增方式
- 遞增時加鎖 sync
- 原子類AtomicXXX (CAS)
- LongAdder
多線程對一個數(shù)進(jìn)行遞增這個事兒竭鞍,我們工作中經(jīng)常會碰上县恕,比如在秒殺時候宿稀。那么這三種方式那種效率更搞一些呢?許多測試來看AtomicXXX比不上sync愕难,但是在我的測試上來看哈垢,起碼在測試條件下AtomicXXX比sync的效率要高很多妻柒。我們來看程序,count1,count2,cunt3分別是一下不同的方式實現(xiàn)遞增耘分,一上來啟動了1000個線程(線程比較多举塔,少了模擬不了高并發(fā))
/**
* @author haowq 2021/2/28 14:29
*/
public class PerformCompare {
static AtomicLong count1 = new AtomicLong(0L);
static long count2 = 0L;
static LongAdder count3 = new LongAdder();
public static void main(String[] args) throws InterruptedException {
Thread[] threads = new Thread[1000];
//方式1 sync
for (int i = 0; i < threads.length; i++) {
threads[i] = new Thread(() -> {
for (int k = 0; k < 100000; k++) count1.incrementAndGet();
});
}
long start = System.currentTimeMillis();
for (Thread t : threads) t.start();
for (Thread t : threads) t.join();
long end = System.currentTimeMillis();
System.out.println("Atomic: " + count1.get() + " time: " + (end - start));
System.out.println("-----------------------------------------------------");
Object lock = new Object();
for (int i = 0; i < threads.length; i++) {
threads[i] = new Thread(() -> {
for (int k = 0; k < 100000; k++) synchronized (lock){count2++;};
});
}
start = System.currentTimeMillis();
for (Thread t : threads) t.start();
for (Thread t : threads) t.join();
end = System.currentTimeMillis();
System.out.println("Sync: " + count2 + " time: " + (end - start));
System.out.println("-----------------------------------------------------");
for (int i = 0; i < threads.length; i++) {
threads[i] = new Thread(() -> {
for (int k = 0; k < 100000; k++) count3.increment();
});
}
start = System.currentTimeMillis();
for (Thread t : threads) t.start();
for (Thread t : threads) t.join();
end = System.currentTimeMillis();
System.out.println("LongAddre: " + count3 + " time: " + (end - start));
System.out.println("-----------------------------------------------------");
}
}
Atomic: 100000000 time: 1615
-----------------------------------------------------
Sync: 100000000 time: 3208
-----------------------------------------------------
LongAddre: 100000000 time: 560
-----------------------------------------------------
Process finished with exit code 0
結(jié)果
LongAdder > Atomic > Sync
分析
為什么Atomic 比Sync快呢,因為sync是要加鎖的陶贼,有可能它要去操作系統(tǒng)申請重量級鎖啤贩,所以sync 效率偏低,在這種情況下效率偏低
為什么LongAdder 比Atomic 效率更高呢拜秧?
LongAdder 的內(nèi)部做了一個分段鎖痹屹,類似于分段鎖的概念。在它內(nèi)部的時候枉氮,會把一個值放到一個數(shù)組中志衍,比如說數(shù)組長度時4,最開始時0聊替,1000個線程楼肪,250個線程鎖在第一個數(shù)組元素里,以此類推惹悄,每一個都往上遞增算出來結(jié)果加到一起春叫。