JDK 8中的LondAddr 与synchronized和AtomicLong并发性能对比实验

目录

 

前文

正文

0. 测试环境

1. Synchronized 测试

2. AtomicLong测试

3. LongAdder测试

总结


前文

       多线程之间常见同步方式 :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要好。

猜你喜欢

转载自blog.csdn.net/u013560925/article/details/89453177
今日推荐