目录
前文
多线程之间常见同步方式 :Synchronized / Lock / volitial + CAS 等,在不同的并发量和不同并发场景下性能不尽相同,尤其是Synchronized在不断经过优化之后性能得到了提升,而且无锁化CAS编程也成为了一些框架提升性能的手段,在JDK 8中,处理已有的原子类之外,添加了LongAdder和LongAccumulator原子类,除去应用场景不说,性能要比原始的原子类性能要好。
LongAdder的实现原理是将原本的value,切分成了多个数组,每个线程单独操作数组中自己对应的值,在获取LongAdder的结果的时候,需要对数组中所有的值进行求和sum操作,LongAccumulator是LongAdder的功能增强版本,原理类似。
正文
以下分别对Synchronized、AtomicLong和LongAdder在多线程下的性能进行简单测试。
0. 测试环境
测试环境就不详细给出了,个人mac pro电脑,编译器:idea ,jdk 8……
1. Synchronized 测试
所需代码:
private static final int MAX_THREADS = 3; //线程数
private static final int TARGET_COUNT = 10000000; //目标总数
//用于统计完成子线程数目
static CountDownLatch cdlsync = new CountDownLatch(MAX_THREADS);
//所需要同步的变量
private long count = 0;
//同步的方法
protected synchronized long getCount(){
return count;
}
protected synchronized long inc(){
//如果不在这里进行越界判断,会出现超出TARGET_COUNT的情况
if(count<TARGET_COUNT){
return ++count;
}
return count;
}
//多线程类
public class SynThread implements Runnable{
private CountDownLatch cdlsync = null;
private long start_time;
private MuilThreadCompare compare=null;
public SynThread(MuilThreadCompare o,CountDownLatch cdlsync,long start_time){
this.compare = o;
this.cdlsync = cdlsync;
this.start_time = start_time;
}
@Override
public void run() {
long re = compare.getCount();
while(re<TARGET_COUNT){
re = compare.inc();
}
long endtime=System.currentTimeMillis();
System.out.println("SyncThread spend:"+(endtime-start_time)+"ms"+" v="+re);
cdlsync.countDown();
}
}
//测试方法
public void testSyn() throws InterruptedException{
ExecutorService pool = Executors.newFixedThreadPool(MAX_THREADS);
long starttime=System.currentTimeMillis();
for (int i = 0; i < MAX_THREADS; i++) {
SynThread thread = new SynThread(this,cdlsync,starttime);
pool.submit(thread);
}
cdlsync.await();
pool.shutdown();
}
结果输入如下所示,使用3个线程,时间稳定在320ms左右,未出现结果越界情况:
2. AtomicLong测试
所需代码如下:
static CountDownLatch cdlatomic=new CountDownLatch(MAX_THREADS);
//原子类
private AtomicLong acount =new AtomicLong(0L);
//线程类
public class AtomicLongThread implements Runnable{
private long start_time;
private AtomicLong atomic = null;
public AtomicLongThread(AtomicLong atomic,long start_time){
this.atomic = atomic;
this.start_time = start_time;
}
@Override
public void run() {
long temp_count = atomic.get();
while(temp_count<TARGET_COUNT){
// 不要用incrementAndGet 方法,否则会出现结果越界情况
//temp_count = atomic.incrementAndGet();
atomic.compareAndSet(temp_count,temp_count+1);
temp_count++;
}
long end_time=System.currentTimeMillis();
System.out.println("AtomicThread spend:"+(end_time-start_time)+"ms"+" v="+temp_count);
cdlatomic.countDown();
}
}
//测试方法:
public void testAtomicLong() throws InterruptedException{
ExecutorService pool = Executors.newFixedThreadPool(MAX_THREADS);
long starttime=System.currentTimeMillis();
for (int i = 0; i < MAX_THREADS; i++) {
AtomicLongThread thread = new AtomicLongThread(acount,starttime);
pool.submit(thread);
}
cdlatomic.await();
pool.shutdown();
}
结果如下图所示,稳定在370ms左右,未出现结果越界情况,一开始的时候使用incrementAndGet API更新值会出现结果越界的情况:
3. LongAdder测试
所需代码:
static CountDownLatch cdladdr=new CountDownLatch(MAX_THREADS);
//新原子类
private LongAdder lacount=new LongAdder();
//线程类
public class LongAdderThread implements Runnable{
private long start_time;
private LongAdder longAdder = null;
public LongAdderThread(long start_time,LongAdder longAdder){
this.start_time = start_time;
this.longAdder = longAdder;
}
@Override
public void run() {
long v = longAdder.sum();
while(v<TARGET_COUNT){
longAdder.increment();
v=longAdder.sum();
}
long end_time=System.currentTimeMillis();
System.out.println("LongAdder spend:"+(end_time-start_time)+"ms"+" v="+v);
cdladdr.countDown();
}
}
//测试方法
public void testLongAdder() throws InterruptedException{
ExecutorService pool = Executors.newFixedThreadPool(MAX_THREADS);
long starttime=System.currentTimeMillis();
for (int i = 0; i < MAX_THREADS; i++) {
LongAdderThread thread = new LongAdderThread(starttime,lacount);
pool.submit(thread);
}
cdlatomic.await();
pool.shutdown();
}
结果如下图所示,时间稳定在180ms左右,但是存在结果值越界的情况,应为:
在更新值的时候,先获取的value的值,然后原子增加,期间可能插入其他线程的操作,导致结果越界。
总结
测试的线程数目不多,3个线程,在低线程数目的情况下,新的原子类表现要比普通原子类和Synchronized性能优良,类推多线程数更多的情况下,LongAdder表现会更好,增加到10线程数的时候,LongAdder:200ms AtomicLong:1330ms Synchronized:384ms ,继续增加线程数差距会越大。
证明LongAdder性能优良的同时,比较意外的是Synchronized性能同样很好,甚至超过了普通的原子类,限制于机器性能,没有测试测试线程数更多的情况,看来低线程的时候,Synchronized要比自旋CAS要好。