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实现了线程安全的数量变化。