Java中 i++ 是线程安全的么?为什么?
Posted 0820LL
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java中 i++ 是线程安全的么?为什么?相关的知识,希望对你有一定的参考价值。
问题
在 int i = 0; i = i++; 语句中,i = i++是线程安全的么?如果不安全,请说明上面操作在JVM中的执行过程,为什么不安全?说出JDK中哪个类能达到以上的效果,并且是线程安全而且高效的,简述其原理。
回答
语句 i = i++;不是线程安全的。
该语句执行过程如下,
先把 i 的值取出来放到栈顶,可以理解为引入了一个第三方变量 k,此时,k的值为i,
然后执行自增操作,i的值变为1,
最后执行赋值操作 i = k (自增前的值)
因此执行结束后,i的值还是0.
从上面的分析可知,i = i++语句的执行过程有多个操作组成,不是原子操作,因此不是线程安全的。
在Java语言中,++i和i++操作并不是线程安全的,在使用的时候,不可避免的会用到synchronized关键字。而java.util.concurrent.AtomicInteger是一个提供原子操作的Integer类,其提供了线程安全且高效的原子操作,是线程安全的。
AtomicInteger类的底层实现原理是利用处理器的CAS操作(Compare And Swap,比较与交换,一种有名的无锁算法)来检测栈中的值是否被其他线程改变,如果被改变则CAS操作失败。这种实现方法在CPU指令级别实现了原子操作,因此,其比使用synchronized来实现同步效率更高。
CAS操作过程都包含三个运算符:内存地址V、期望值E、新值N。当操作的时候,如果地址V上存放的值等于期望值E,则将地址V上的值赋为新值N,否则,不做任何操作,但是要返回原值是多少。这就保证比较和设置这两个动作是原子操作。系统主要利用JNI(Java Native Interface,Java本地接口)来保证这个原子操作,它利用CPU硬件支持来完成,使用硬件提供swap和test_and_set指令,但CPU下同一指令的多个指令周期不可中断,SMP(Symmetric Multi-Processing)中通过锁总线支持这两个指令的原子性。
以上是关于Java中 i++ 是线程安全的么?为什么?的主要内容,如果未能解决你的问题,请参考以下文章
Spring8Spring框架中的单例Beans是线程安全的么