java - += 运算符在 Java 中是线程安全的吗?

标签 java multithreading

我找到了以下 Java 代码。

for (int type = 0; type < typeCount; type++)
    synchronized(result) {
        result[type] += parts[type];
    }
}

其中 resultpartsdouble[]

我知道基本类型的基本操作是线程安全的,但我不确定 +=。如果上述 synchronized 是必要的,是否有更好的类来处理这种操作?

最佳答案

没有。 += 操作不是线程安全的。对于涉及分配给共享字段或数组元素的任何表达式,它需要锁定和/或适当的“之前发生”关系链,才能实现线程安全。

(使用声明为 volatile 的字段,存在“之前发生”关系...但仅在读取和写入操作中。+= 操作包括一个读和一个写。这些是单独的原子,但序列不是。大多数使用 = 的赋值表达式都涉及一个或多个读取(在右侧)和一个写入。那 < em>sequence 也不是原子的。)

要了解完整的故事,请阅读 JLS 17.4 ...或 Brian Goetz 等人的“Java Concurrency in Action”的相关章节。

As I know basic operations on primitive types are thread-safe ...

其实这是一个不正确的前提:

  • 考虑数组的情况
  • 请考虑表达式通常由一系列操作组成,并且不能保证一系列原子操作是原子的。

double 类型还有一个问题。 JLS (17.7) 是这样说的:

"For the purposes of the Java programming language memory model, a single write to a non-volatile long or double value is treated as two separate writes: one to each 32-bit half. This can result in a situation where a thread sees the first 32 bits of a 64-bit value from one write, and the second 32 bits from another write."

"Writes and reads of volatile long and double values are always atomic."


在评论中,您问:

So what type I should use to avoid global synchronization, which stops all threads inside this loop?

在这种情况下(您要更新 double[],除了与锁或原始互斥锁同步之外别无选择。

如果您有 int[]long[],您可以将它们替换为 AtomicIntegerArrayAtomicLongArray 并利用这些类的无锁更新。但是没有 AtomicDoubleArray 类,甚至没有 AtomicDouble 类。

(更新 - 有人指出 Guava 提供了一个 AtomicDoubleArray 类,所以 是一种选择。实际上是一个很好的选择。)

避免“全局锁”和大量争用问题的一种方法可能是将数组划分为概念区域,每个区域都有自己的锁。这样,一个线程只需要阻塞另一个线程,如果它们正在使用数组的相同区域。 (单写/多读锁也有帮助......如果绝大多数访问都是读取。)

关于java - += 运算符在 Java 中是线程安全的吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32676771/

相关文章:

java - Android 在 onCreate() 之外使用 javascript/java 桥设置软输入模式

java - 如何使用 iText 7 检查现有文档的 PDF/A 一致性?

C 测试问题中的循环缓冲区实现

java - 使用并发、线程、静态变量实现 GAE/Java 计数器

c++ - (Qt5,线程)我正在关注的示例不起作用

java - 使用 WebSphere MQ v7.0 找不到 SYSTEM.BROKER 服务

java - JEdi​​torPane.getPreferredSize 并不总是在 Java 9 中工作?

java - Spring Boot jpa 中多对一映射中的子表中的外键未更新

c++ - 如何编写线程安全的自动化测试

java - 如何正确创建 SynchronizedStack 类?