最近招聘经常会问到别人i++和++i的区别,于是这里来总结一下,当然除了那个大家都知道的先加后加的区别;
在性能上的区别
1.i++,会创建一个tmp值来保存i值,所有会额外带来开销,而++i不会。当然这个性能区别不会特别明显,基本上可以忽略。
原子性比较
1.i++和++i是否都具有原子性?
答案是否定的,均不具有原子性,我们可以通过多线程来试一下是否是线程安全就明白了。
public class TestForBlock { static volatile Integer k=0; public static void main(String[] args) throws InterruptedException { Thread[] ts = new Thread[1000]; for(int i=0;i<1000;i++){ ts[i]=new Thread(){ public void run(){ try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } ++k; //也可替换成k++再试一下 } }; } for (Thread t:ts) { t.start(); } for (Thread t:ts) { t.join(); } System.out.println(k); } }
输出结果期望应该是为1000,但是结果并不是1000,可能是小于1000的某个值。
这里的k变量使用了volatile定义,也就是说保证了内存可见性,但是volatile并不能保证原子性,如果i++或++i具有原子性,那么输出结果应该是1000才对。
那如果想让i++具有原子性怎么解决?
方法一、通过加上同步关键字synchronized
方法二、通过使用原子类AtomicInteger
比如讲k的定义换成这个final AtomicInteger k=new AtomicInteger(0); 就能保证起++的原子性;
这里讲下碰到的一个问题,当把k替换成原子类后,并且将下面代码去掉
for (Thread t:ts) {
t.join();
}
最后的输出结果是什么样的? 会不会有影响?
运行后,发现输出结果是840多,并不是1000, 是什么问题? 难道原子类也不具有原子性?
如果对join比较明白的话就会明白是怎么回事了。因为有1000个线程执行,每个线程均有sleep(10),这样导致子线程还未执行完就到了主线程来执行了,所以输出结果就不是1000了。
加上join后,会等待所有线程执行完毕,再执行主线程。
join后面单独再拿一篇文章来说明吧