java i++ 计数器的性能测试

java ‘i++’ 计数器的性能测试前言在写多线程中,我们免不了使用到计数器,今天就来分析下java中提供给我们的计数器以及它们的性能测试。1.所谓的volatile

上一篇文章我也写到了volatile的作用:当我们写一个变量时,它会被立刻刷新到主内存中去,保证了变量对其他线程的可见性,不会发生线程在自己的私有内存中更新了数据却没有同步到主内存中。并且在后来的JDK版本volatile语义被增强,它会限定部分内存重排的规则来保证线程安全性 虽然volatile用来保证线程安全性,但是我们要注意volatile修饰的变量并不是线程安全的。也就是说volatile只是起 辅助 作用,它不保证修饰的变量是原子的。

来看段简单的代码:

{i = 0;(String args[]) throws InterruptedException{class NewThread extends Thread {() {for (int j = 0; j < 1000000; ++j) {++i;}}}double start = System.currentTimeMillis();NewThread nt1 = new NewThread();NewThread nt2 = new NewThread();NewThread nt3 = new NewThread();nt1.start();nt2.start();nt3.start();nt1.join();nt2.join();nt3.join();double end = System.currentTimeMillis();System.out.println(i);System.out.println(“time:” + (end-start));}}

从图片我们可以看出volatile修饰的变量是不保证原子性的(正确结果应该是3000000),原因比如线程A和线程B同时操作i时,A,B线程同时更新了本地,然后两个线程同时刷新到内存中问题就出现了。但是随着JVM的优化,volatile的用处也越来越少了,我们可以使用后面将要说的几种,然而一般用volatile修饰boolean类型是个不错的主意。 注意:volatile修饰和自己本身无关的变量操作时是原子的,n++不是,但若n = m+1或者 n = ture是原子的,原因可以想想volatile的原理。

2.Synchronized同步原语

Synchronized可以修饰一个方法或者一个代码块,并且在某一时刻保证只有一个线程可以访问这个方法或者代码块。 Synchronized原理其实就是java中每个对象都有一个监视器,或叫做锁,当访问该对象Synchronized方法或代码块是就会上锁,直到访问完毕或者抛出异常才会释放锁。 由此可见Synchronized是保证能同步的,毕竟涉及到了lock锁机制,但是效率相对来说也是比较低的,毕竟涉及到加锁和解锁,而且在加锁的情况下其他线程访问也会被阻塞。

代码

{i = 0;incre(){++i;}(String args[]) throws InterruptedException {class NewThread extends Thread{(){for(int j = 0; j < 1000000; ++j){incre();}}}double start = System.currentTimeMillis();NewThread nt1 = new NewThread();NewThread nt2 = new NewThread();NewThread nt3 = new NewThread();nt1.start();nt2.start();nt3.start();nt1.join();nt2.join();nt3.join();double end = System.currentTimeMillis();System.out.println(i);System.out.println(end-start);}}

结果:

3.JDK1.5的AtomicLong

java se5引入了AtomicLong这个原子类,为我们封装了类似i++的操作,所以我们可以直接简单的使用。

{(String args[]) throws InterruptedException {//AtomicInteger i = new AtomicInteger(0);AtomicLong i = new AtomicLong(0);class NewThread extends Thread{(){for(int j = 0; j < 1000000; ++j) {i.addAndGet(1);}}}double start = System.currentTimeMillis();NewThread nt1 = new NewThread();NewThread nt2 = new NewThread();NewThread nt3 = new NewThread();nt1.start();nt2.start();nt3.start();nt1.join();nt2.join();nt3.join();double end = System.currentTimeMillis();System.out.println(i.get());System.out.println(end-start);}}

代码中我注释了AtomicInteger,是原子整型,AtomicLong是长整型,在实际测试过程中AtomicInteger速度要比AtomicLong快 下图是AtomicInteger

所以,我们是选择计数器时还是要根据实际情况选择并且根据自己的机器情况来选择效率最高的。

4.Java8 LongAddr Vs AtomicLong

最新的java8更新了不少东西,其中就包括新的原子计数器LongAddr,既然它能更新进来说明它的效率是更好的^_^,使用和前面的AtomicLong没什么区别,而且它其实就是用来代替AtomicLong的。

看代码:

{(String args[]) throws InterruptedException {LongAdder la = new LongAdder();class CountThread extends Thread{(){for(int i = 0; i < 1000000; ++i){la.increment();}}}double start = System.currentTimeMillis();CountThread ct1 = new CountThread();CountThread ct2 = new CountThread();CountThread ct3 = new CountThread();ct1.start();ct2.start();ct3.start();ct1.join();ct2.join();ct3.join();double end = System.currentTimeMillis();System.out.println(la);System.out.println(end-start);}}

风景如何,其实并不重要。重要的是,你在我的身边。

java i++ 计数器的性能测试

相关文章:

你感兴趣的文章:

标签云: