原子类LongAdder
LongAdder实现的思想:核心是将热点数据分离,把AtomicLong的内部核心数据value分离为一个数组,每个线程访问时通过hash等算法映射到其中一个数字进行计数,最终的结果是这个数组的求和累加。其中热点数据value被分为多个单元的cell,每个cell独自维护内部的值,当前对象实际的值由所有的cell累计合成。这样,
热点进行了有效分离并提高了并行度,LongAdder在AtomicLong的基础上将单点的更新压力分散到各个节点上,
低并发的时候通过对base的直接更新保证和atomic的性能基本一致,高并发通过分散提高性能。并发更新有误差,高并发计数优先使用LongAdder
@ThreadSafe
public class ConcurrencyByLongAdder {
//请求总数
private static int clientTotal = 10000;
//并发数
private static int threadTotal = 100;
public LongAdder count = new LongAdder();
public static void main(String[] args) {
ConcurrencyByLongAdder test = new ConcurrencyByLongAdder();
// 使用并发库,创建缓存的线程池
ExecutorService executor = Executors.newCachedThreadPool();
// 创建一个Semaphore信号量,并设置最大并发数为
final Semaphore semaphore = new Semaphore(threadTotal);
//希望所有线程结束再返回主线程,所以是请求总数
final CountDownLatch countDownLatch = new CountDownLatch(clientTotal);
// 创建10个任务,上面的缓存线程池就会创建10个对应的线程去执行
for (int i = 0; i < clientTotal; i++) {
final int NO = i; // 记录第几个任务
Runnable task =
new Runnable() {
@Override
public void run() {
try {
semaphore.acquire(); // 获取许可
test.add();
semaphore.release(); // 释放许可
} catch (InterruptedException e) {
e.printStackTrace();
}
countDownLatch.countDown();
}
};
executor.submit(task); // 执行任务
}
try {
System.out.println("等待线程池任务执行完毕...");
countDownLatch.await();
System.out.println("线程池执行任务已经执行完毕");
System.out.println("继续执行主线程");
} catch (InterruptedException e) {
e.printStackTrace();
}
if (!executor.isShutdown()) {
executor.shutdown();
System.out.println("shutdown ...");
}
int count = test.count.intValue();
System.out.println(count);
}
private void add() {
count.increment();
}
}
这里可以参考阿里巴巴的开发手册,在1.8之后,优先是用LongAdder