本文正在参加「Java主题月 - Java Debug笔记活动」,详情查看 活动链接
Debug 笔记 <Java中的+ =运算符是线程安全的吗?>
提问
我找到了以下Java代码。
for (int type = 0; type < typeCount; type++)
synchronized(result) {
result[type] += parts[type];
}
}
我知道基本类型的基本操作是线程安全的,但是我不确定+=。如果上述synchronized是必要的,
是否可能有更好的类来处理这种操作?
回答一
否。
该+=操作不是线程安全的。对于涉及分配给共享字段或数组元素的任何表达式来说,它要求锁定和/或适当的“先于”关系链是线程安全的。
(在字段声明为volatile的情况下,“先发生”关系存在...但是仅在读和写操作上存在。该+=操作由读和写组成。它们分别是原子的,但顺序不是。大多数使用的赋值表达式=涉及一个或多个读取(在右侧)和写入。该序列也不是原子的。)
回答二
尽管Java中没有AtomicDouble或AtomicDoubleArray,
您仍然可以轻松地基于创建自己的Java AtomicLongArray。
static class AtomicDoubleArray {
private final AtomicLongArray inner;
public AtomicDoubleArray(int length) {
inner = new AtomicLongArray(length);
}
public int length() {
return inner.length();
}
public double get(int i) {
return Double.longBitsToDouble(inner.get(i));
}
public void set(int i, double newValue) {
inner.set(i, Double.doubleToLongBits(newValue));
}
public void add(int i, double delta) {
long prevLong, nextLong;
do {
prevLong = inner.get(i);
nextLong = Double.doubleToLongBits(Double.longBitsToDouble(prevLong) + delta);
} while (!inner.compareAndSet(i, prevLong, nextLong));
}
}
正如你所看到的,我使用Double.doubleToLongBits与Double.longBitsToDouble存储Doubles为Longs在AtomicLongArray。它们的位大小相同,因此精度不会丢失(-NaN除外,但我认为这并不重要)。
在Java 8中,实现add可以更加轻松,因为您可以使用Java 1.8中添加的accumulateAndGet方法AtomicLongArray。
回答三
在32位JVM中,即使是普通的“双精度”数据类型也不是线程安全的(因为它不是原子的),因为在Java中它占用了八个字节(涉及2 * 32位操作)。
文章翻译自Stack Overflow :stackoverflow.com/questions/3…