你們對AtomicInteger的基本實現機制應該比較瞭解,它們是在一個死循環內,不斷嘗試修改目標值,知道修改爲功,若是競爭不激烈,那麼修改爲功的機率就很高,不然,修改失敗的機率就很高,在大量修改失敗時,這些原子操做就會進行屢次循環嘗試,所以性能就會受到影響
那麼競爭激烈的時候,咱們應該如何進一步提升系統性能呢?一種基本方案就是可使用熱點分離,將競爭的數據進行分解.基於這個思路,打擊應該能夠想到一種對傳統AtomicInteger等原子類的改進方法,雖然在CAS操做中沒有鎖,可是像減小鎖粒度這種分離熱點的思路依然可使用,一種可行的方案就是仿造ConcurrengHashMap,將熱點數據分離,好比,能夠將AtomicInteger的內部核心數據value分離成一個數組,每一個線程訪問時,經過哈希等算法映射到其中一個數字進行計數,而最終的計數結果,則爲這個數組的求和累加,其中,熱點數據value被分離成多個單元cell,每一個cell獨自維護內部的值,當前對象的實際值由全部的cell累計合成,這樣,熱點就進行了有效的分離,提升了並行度,LongAdder正是使用了這種思想.
public class LongAdderDemo {
private static final int MAX_THREADS = 3;
private static final int TASK_COUNT = 3;
private static final int TARGET_COUNT = 10000000;
private AtomicLong acount = new AtomicLong(0L);
private LongAdder lacount = new LongAdder();
private long count = 0;
private static CountDownLatch cdlsync = new CountDownLatch(TASK_COUNT);
private static CountDownLatch cdlatomic = new CountDownLatch(TASK_COUNT);
private static CountDownLatch cdladdr = new CountDownLatch(TASK_COUNT);
protected synchronized long inc() {
return ++count;
}
protected synchronized long getCount() {
return count;
}
public class SyncThread implements Runnable {
protected String name;
protected long starttime;
LongAdderDemo out;
public SyncThread(long starttime, LongAdderDemo out) {
this.starttime = starttime;
this.out = out;
}
@Override
public void run() {
long v = out.getCount();
while (v < TARGET_COUNT) {
v = out.inc();
}
long endtime = System.currentTimeMillis();
System.out.println("SyncThread spend:" + (endtime - starttime) + "ms" + " v" + v);
cdlsync.countDown();
}
}
public void testSync() throws InterruptedException {
ExecutorService exe = Executors.newFixedThreadPool(MAX_THREADS);
long starttime = System.currentTimeMillis();
SyncThread sync = new SyncThread(starttime, this);
for (int i = 0; i < TASK_COUNT; i++) {
exe.submit(sync);
}
cdlsync.await();
exe.shutdown();
}
public class AtomicThread implements Runnable {
protected String name;
protected long starttime;
public AtomicThread(long starttime) {
this.starttime = starttime;
}
@Override
public void run() {
long v = acount.get();
while (v < TARGET_COUNT) {
v = acount.incrementAndGet();
}
long endtime = System.currentTimeMillis();
System.out.println("AtomicThread spend:" + (endtime - starttime) + "ms" + " v" + v);
cdlatomic.countDown();
}
}
public void testAtomic() throws InterruptedException {
ExecutorService exe = Executors.newFixedThreadPool(MAX_THREADS);
long starttime = System.currentTimeMillis();
AtomicThread atomic = new AtomicThread(starttime);
for (int i = 0; i < TASK_COUNT; i++) {
exe.submit(atomic);
}
cdlatomic.await();
exe.shutdown();
}
public class LongAdderThread implements Runnable {
protected String name;
protected long starttime;
public LongAdderThread(long starttime) {
this.starttime = starttime;
}
@Override
public void run() {
long v = lacount.sum();
while (v < TARGET_COUNT) {
lacount.increment();
v = lacount.sum();
}
long endtime = System.currentTimeMillis();
System.out.println("LongAdderThread spend:" + (endtime - starttime) + "ms" + " v" + v);
cdladdr.countDown();
}
}
public void testLongAdder() throws InterruptedException {
ExecutorService exe = Executors.newFixedThreadPool(MAX_THREADS);
long starttime = System.currentTimeMillis();
LongAdderThread atomic = new LongAdderThread(starttime);
for (int i = 0; i < TASK_COUNT; i++) {
exe.submit(atomic);
}
cdladdr.await();
exe.shutdown();
}
public static void main(String[] args) throws InterruptedException {
LongAdderDemo demo = new LongAdderDemo();
demo.testSync();
demo.testAtomic();
demo.testLongAdder();
}
}