面试题整理:多线程中的i++线程安全吗?

多线程中的i++线程安全吗?请简述一下原因?

不安全。因为i++不是原子性操作。i++分为读取i值,对i值加1,再赋值给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)中通过锁总线支持这两个指令的原子性。

发布了18 篇原创文章 · 获赞 4 · 访问量 917

猜你喜欢

转载自blog.csdn.net/weixin_43698561/article/details/104347747