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)中通过锁总线支持这两个指令的原子性。

猜你喜欢

转载自www.cnblogs.com/0820LL/p/9695336.html