前言
在开发的过程中,单机并发修改共享数据的场景是尤为要注意的(其实很少遇到),而目前流行的解决手段,不是加锁就是使用CAS,本文旨在探究 sychronized锁、AtomicInteger、LongAdder这些解决方案之间的性能差异。
结果如下:
18:04:38.996 [main] INFO demo.server.cas.CasTest - 当前核心数:12
18:04:38.996 [main] INFO demo.server.cas.CasTest - ===================================
18:04:39.487 [main] INFO demo.server.cas.CasTest - SimpleExecutor执行10次结果:[96048, 97223, 96854, 97761, 98289, 98271, 97692, 98318, 99089, 99040]
18:04:39.487 [main] INFO demo.server.cas.CasTest - SimpleExecutor平均调用时长:49
18:04:39.487 [main] INFO demo.server.cas.CasTest - ===================================
18:04:39.889 [main] INFO demo.server.cas.CasTest - SyncLockExecutor执行10次结果:[99999, 99999, 99999, 99999, 99999, 99999, 99999, 99999, 99999, 99999]
18:04:39.889 [main] INFO demo.server.cas.CasTest - SyncLockExecutor平均调用时长:40
18:04:39.889 [main] INFO demo.server.cas.CasTest - ===================================
18:04:40.296 [main] INFO demo.server.cas.CasTest - AtomicExecutor执行10次结果:[99999, 99999, 99999, 99999, 99999, 99999, 99999, 99999, 99999, 99999]
18:04:40.296 [main] INFO demo.server.cas.CasTest - AtomicExecutor平均调用时长:40
18:04:40.296 [main] INFO demo.server.cas.CasTest - ===================================
18:04:40.559 [main] INFO demo.server.cas.CasTest - LongAdderExecutor执行10次结果:[99999, 99999, 99999, 99999, 99999, 99999, 99999, 99999, 99999, 99999]
18:04:40.559 [main] INFO demo.server.cas.CasTest - LongAdderExecutor平均调用时长:26
这里要补充一下,理论上从性能方面来说,不作处理 > LondAdder(分治法CAS) > AtomicInteger(CAS) > Synchronized(相当于单核串行了)
那会不会是线程池里的大部分线程没有工作,导致操作几乎是串行化的,所以不同方案性能差异不大呢?答案是不可能的,因为根据SimpleExecutor的执行结果来看确实存在并发问题,说明多个线程(cpu)同时修改数据的情况是存在的。当然我们可以加上以下代码观察一下结果:
...
13:32:51.981 [pool-1-thread-5] INFO demo.server.cas.CasTest - 当前由线程pool-1-thread-5为您操作
13:32:51.981 [pool-1-thread-6] INFO demo.server.cas.CasTest - 当前由线程pool-1-thread-6为您操作
13:32:51.981 [pool-1-thread-12] INFO demo.server.cas.CasTest - 当前由线程pool-1-thread-12为您操作
13:32:51.981 [pool-1-thread-3] INFO demo.server.cas.CasTest - 当前由线程pool-1-thread-3为您操作
...
从结果来看,确实12条线程都跑起来了。
附上完整代码
package demo.server.cas;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StopWatch;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.LongAdder;
@Slf4j
public class CasTest {
private static final ThreadPoolExecutor EXECUTOR = new ThreadPoolExecutor(12,24,2000, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<>(100000));
public static void main(String[] args) throws ExecutionException, InterruptedException {
log.info("当前核心数:{}",Runtime.getRuntime().availableProcessors());
new SimpleExecutor().execute();
new SyncLockExecutor().execute();
new AtomicExecutor().execute();
new LongAdderExecutor().execute();
EXECUTOR.shutdown();
}
static class LongAdderExecutor extends Executor<LongAdder>{
@Override
protected LongAdder getCounter() {
return new LongAdder();
}
@Override
protected void countImcrement(LongAdder count) {
count.increment();
}
@Override
protected int getCountValue(LongAdder count) {
return count.intValue();
}
}
static class AtomicExecutor extends Executor<AtomicInteger>{
@Override
protected AtomicInteger getCounter() {
return new AtomicInteger();
}
@Override
protected void countImcrement(AtomicInteger count) {
count.incrementAndGet();
}
@Override
protected int getCountValue(AtomicInteger count) {
return count.get();
}
}
static class SyncLockExecutor extends Executor<Result>{
@Override
protected Result getCounter() {
return new Result(0L,0);
}
@Override
protected void countImcrement(Result count) {
synchronized(this){
count.count++;
}
}
@Override
protected int getCountValue(Result count) {
return count.getCount();
}
}
static class SimpleExecutor extends Executor<Result>{
@Override
protected Result getCounter() {
return new Result(0L,0);
}
@Override
protected void countImcrement(Result count) {
count.count += 1;
if (count.count%333 ==0){
log.info("当前由线程{}为您操作",Thread.currentThread().getName());
}
}
@Override
protected int getCountValue(Result count) {
return count.getCount();
}
}
static abstract class Executor<V>{
/**
* 执行一组测试
* @throws ExecutionException
* @throws InterruptedException
*/
public void execute() throws ExecutionException, InterruptedException {
log.info("===================================");
//参数准备
int times = 10;
long totalTimeMillis = 0L;
List<Integer> counts = new ArrayList<>();
String simpleName = this.getClass().getSimpleName();
//获取多次执行结果
for (int i = 0; i < times; i++) {
Result result = doExecute();
totalTimeMillis += result.getExecuteTime();
counts.add(result.getCount());
}
log.info("{}执行{}次结果:{}", simpleName,times, counts);
log.info("{}平均调用时长:{}", simpleName,totalTimeMillis/times);
}
/**
* 执行一次测试
* @return
* @throws ExecutionException
* @throws InterruptedException
*/
public Result doExecute() throws ExecutionException, InterruptedException {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
//为了保证逻辑清晰,测试结果串行处理
List<Future> futures = new ArrayList<>();
final V count = getCounter();
//单个测试计算99999次,调用线程池异步执行
for (int i = 0; i < 99999; i++) {
Future<?> future = EXECUTOR.submit(() -> {
countImcrement(count);
});
futures.add(future);
}
for (Future future : futures) {
future.get();
}
stopWatch.stop();
long totalTimeMillis = stopWatch.getTotalTimeMillis();
return new Result(totalTimeMillis,getCountValue(count));
}
protected abstract V getCounter();
protected abstract void countImcrement(V count);
protected abstract int getCountValue(V count);
}
@Data
@AllArgsConstructor
static class Result{
private Long executeTime;
private Integer count;
}
}