在计数的时候,有两个类LongAddr和AtomicInteger属于线程安全的并发类。但是各有千秋
先看如下案例
public class LongAddrMain {
public static void main(String[] args) throws InterruptedException {
LongAdder longAdder=new LongAdder();
ExecutorService executors=Executors.newFixedThreadPool(10);
for (int i = 0; i <100 ; i++) {
executors.submit(new Task(longAdder));
}
Thread.sleep(2000);
System.out.println(longAdder.sum());
}
static class Task implements Runnable{
LongAdder longAdder;
Task(LongAdder longAdder){
this.longAdder=longAdder;
}
@Override
public void run() {
longAdder.increment();
}
}
}
public class Main {
public static void main(String[] args) throws InterruptedException {
AtomicLong counter=new AtomicLong(0);
ExecutorService service= Executors.newFixedThreadPool(16);
for (int i = 0; i <100 ; i++) {
service.submit(new Task(counter));
}
Thread.sleep(2000);
System.out.println(counter.get());
}
static class Task implements Runnable{
private AtomicLong counter;
Task(AtomicLong counter){
this.counter=counter;
}
@Override
public void run() {
counter.incrementAndGet();
}
}
}
LongAddr的吞吐量要比AtomicInteger大许多,性能相对要好,但是内存也需要付出一定的代价
但是因为什么付出这么大的代价呢?
/**
* Adds the given value.
*
* @param x the value to add
*/
public void add(long x) {
Cell[] as; long b, v; int m; Cell a;
if ((as = cells) != null || !casBase(b = base, b + x)) {
boolean uncontended = true;
if (as == null || (m = as.length - 1) < 0 ||
(a = as[getProbe() & m]) == null ||
!(uncontended = a.cas(v = a.value, v + x)))
longAccumulate(x, null, uncontended);
}
}
/**
* Returns the current sum. The returned value is <em>NOT</em> an
* atomic snapshot; invocation in the absence of concurrent
* updates returns an accurate result, but concurrent updates that
* occur while the sum is being calculated might not be
* incorporated.
*
* @return the sum
*/
public long sum() {
Cell[] as = cells; Cell a;
long sum = base;
if (as != null) {
for (int i = 0; i < as.length; ++i) {
if ((a = as[i]) != null)
sum += a.value;
}
}
return sum;
}
究其源码,可以发现在LongAddr中有Cell[]这个字段,它是用来进行分段处理的,看一眼sum的方法可知,LongAddr中有个base的参数,当cell的数值汇总到sum中去,这个与ConcurrentHashMap中的类似,也是使用了分治的思想,提高了效率,减少了碰撞发生的可能。
那么,什么时候该用AtomicInteger什么时候用LongAddr呢?
普通来讲,LongAddr吞吐是AtomicInteger的10倍左右,在Add,Increase等方面有着很强的性能,但是AtomicInteger有着更广泛的应用场景,里面的compareAndSwap方法更适用于有CAS这种业务需要的场景之中。