Java中 ++i 的操作是线程安全的么?
- 如果是方法里定义的局部变量,一定是线程安全的,因为每个方法栈是线程私有的。
- 如果是类的成员变量,
++i则不是线程安全的,因为++i相当于i = i + 1,可以通过synchronize块来提供同步,也可使用AtomicInteger原子操作类,这里同步体比较小(++i),推荐使用自旋CAS实现的AtomicInteger。 volatile不能解决这个线程安全问题。因为volatile只能保证可见性,不能保证原子性。
保证线程安全的 AtomicInteger
在 JDK 1.5 之后,Java程序才可以使用CAS操作,该操作由 sun.misc.Unsafe 类里面的 compareAndSwapInt() 和 compareAndSwapLong() 等几个方法包装提供,虚拟机编译出来的结果就是一条平台相关的处理器CAS指令。
由于Unsafe类不是提供给用户程序调用的类(Unsafe.getUnsafe() 的代码中限制了只有启动类加载器(Bootstrap ClassLoader)加载的Class才能访问它),因此如果不使用反射手段,我们只能通过其他的Java API来间接使用它,如 JUC 包里的 AtomicInteger 类,其中 incrementAndGet() 等方法都使用了Unsafe类的CAS操作。
JDK 8 源码实现:
public final int incrementAndGet() { // 增加1,并返回结果
return unsafe.getAndAddInt(this, valueOffset, 1) + 1;
}
public final int getAndAddInt(Object o, long offset, int delta) {
int v;
do { // 自旋
v = getIntVolatile(o, offset);
} while (!compareAndSwapInt(o, offset, v, v + delta)); // CAS 操作
return v;
}
可以看到 AtomicInteger 通过自旋CAS实现了线程安全的数量变化。
探讨Java中++i操作的线程安全性,局部变量因方法栈私有而安全,成员变量需synchronize或AtomicInteger确保。AtomicInteger通过自旋CAS实现线程安全。
10万+

被折叠的 条评论
为什么被折叠?



