BigInteger 线程安全吗?

Is BigInteger Thread safe?

我需要通过多线程更新全局 BigInteger 值 -- BigInteger 线程安全吗?

java.math.BigInteger 是不可变的,因此对于多线程访问是安全的。

旁注:Thread-safety 是一个术语,用于处理多个线程访问 一段代码 (不仅仅是一个变量)。

您无法更新 BigInteger,请阅读 javadoc,它是不可变的任意精度整数。。要更新 BigInteger 字段,您需要将其替换为新的 BigInteger,如下所示

...
bigInteger = bigInteger.add(value);
...

这将需要同步,否则可能会发生两种情况:

  1. 一个线程更改了值但其他线程看不到更改

  2. 两个或多个线程正在同时添加,但一些添加丢失了。

BigInteger 是线程安全的。 但是你想更新它,你应该使用这样的代码:

private BigInteger bigInteger = BigInteger.ONE;

public void add(BigInteger plus) {
    bigInteger = bigInteger.add(plus);
}

所以同步是必要的。

BigInteger objects are an representative example of immutable objects.
简单地说:

Each immutable object is thread-safe, but the reference to it is not.

对于不可变对象,状态在整个生命周期内都是固定的。因为没有更改它的选项,所以每个 "change" 操作等同于用新对象替换。因此,在 N 个线程对特定引用并行执行一系列修改后,结果值很难预测(一些更新可能会丢失 - 未被注意到)。
同样的故事发生在 Integer class. To overcome that limitation AtomicInteger class was introduced to JDK5.
不幸的是,JDK 中没有“AtomicBigInteger”class。替代解决方案是使用 AtomicReference 包装一个对象实例 - 它作为代理使所有操作同步和原子化。

我提出以下紧凑的解决方案,需要 JDK 8:

final AtomicReference<BigInteger> valueHolder = new AtomicReference(BigInteger.ZERO);

使用这种方法,BigInteger 提供的任何方法都可以重述为 lambda 表达式,例如:

valueHolder.updateAndGet(x -> x.add(BigInteger.valueOf(10)));

要检查解决方案是否正确,您可以使用以下代码片段,它使用并行流(它是多线程操作)对所有小于 100 的整数求和:

IntStream.range(0, 100).parallel()
        .forEach(i -> valueHolder.updateAndGet(x -> x.add(BigInteger.valueOf(i))));

BigInteger : Immutable arbitrary-precision integers.

Immutable Objects : An object is considered immutable if its state cannot change after it is constructed. Maximum reliance on immutable objects is widely accepted as a sound strategy for creating simple, reliable code.

这意味着 BigInteger 是线程安全的。