当前位置: 首页 > 面试题库 >

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

赖淇
2023-03-14
问题内容

我发现以下Java代码。

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

其中,resultpartsdouble[]

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


问题答案:

否。该+=操作不是线程安全的。对于涉及分配给共享字段或数组元素的任何表达式,它要求锁定和/或适当的“先于”关系链是线程安全的。

(在字段声明为volatile的情况下,“先发生”关系存在…但是仅在读和写操作上存在。该+=操作由一个读和一个写操作组成。它们分别是原子的,但是顺序不是。大多数使用的赋值表达式=涉及一个或多个读取(在右侧)和写入。该
序列 也不是原子的。)

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

据我所知,基本类型的基本操作是线程安全的。

实际上,这是一个不正确的前提:

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

double类型还有另一个问题。JLS(17.7)说:

“就Java编程语言内存模型而言,对非易失性long或double值的单次写入被视为两次单独的写入:一次写入每个32位的一半。这可能导致线程看到以下情况:来自一次写入的64位值的前32位,以及来自另一次写入的后32位。”

“易失的long和double值的写入和读取始终是原子的。”

在评论中,您询问:

那么我应该使用哪种类型来避免全局同步,这会停止此循环内的所有线程?

在这种情况下(如果您要更新double[],则无法使用锁或原始互斥锁进行同步。

如果您使用int[]long[],则可以用AtomicIntegerArray或替换它们,AtomicLongArray并利用这些类的无锁更新。但是,没有AtomicDoubleArray课程,甚至没有AtomicDouble课程。

UPDATE -有人指出,番石榴提供了一个AtomicDoubleArray类,这样 是一种选择一个好的实际。)

避免“全局锁定”和大量争用问题的一种方法可能是将数组划分为概念区域,每个区域都有自己的锁定。这样,一个线程仅在使用数组的同一区域时才需要阻塞另一个线程。(如果绝大多数访问是读取的,那么单作家/多读者锁定也可能会有所帮助。)



 类似资料:
  • 问题内容: 我想创建一个非线程安全的代码块进行实验,这些是2个线程将要调用的函数。 此代码线程安全吗? 如果不是,我可以理解为什么它不是线程安全的,以及通常使用哪种语句导致非线程安全的操作。 如果它是线程安全的,如何使它显式地成为非线程安全的? 问题答案: 由于有GIL,单个操作码是线程安全的,但除此之外: *多个线程共享的 *每个 资源都 必须 有一个锁。

  • 问题内容: 我正在用Java编写一个程序,使一些汽车相互竞争。每辆车都是单独的线程。 当汽车完成比赛时,每个人都会调用此方法。我已经在不同的计时器速度下测试了该方法,并且看起来效果很好。但是我确实意识到每个线程都在访问变量carsComplete,有时恰好在同一时间(至少在date命令给我的范围内)。 所以我的问题是:这个方法是线程安全的吗? 问题答案: 不,您应该使用。看看它的方法。

  • 问题内容: Java线程安全性易变吗?也就是说,可以安全地读取和写入它而无需锁定吗? 问题答案: 是的,您可以从中读取并安全地对其进行写入-但您不能做任何复合操作,例如安全地对其进行递增,因为这是一个读/修改/写周期。还有一个问题是它如何与 其他 变量的访问交互。 坦率地说,volatile的确切性质令人困惑(有关更多详细信息,请参见JLS的内存模型部分)-我 个人 通常会使用它作为确保正确使用的

  • 我找到了关于线程安全的代码,但它没有来自给出示例的人的任何解释。我想知道为什么如果我不在“count”之前设置“synchronized”变量,那么count值将是非原子的(总是=200是期望的结果)。谢谢

  • 问题内容: 我知道文档说明该对象是线程安全的,但这是否意味着从所有方法对其进行的所有访问都是线程安全的?因此,如果我一次从多个线程中调用它,并且一次在同一实例上调用它,会不会发生什么不好的事情? 问题答案: 快速答案是肯定的,它们是线程安全的。但是不要让它在那里… 首先,一个小的内部管理是一个接口,任何不是线程安全的实现都将破坏书面合同。您包括的链接是指,它具有一定的灵巧性。 您包含的链接引起了一

  • 本文向大家介绍如何理解Java中的StringBuffer是线程安全的而StringBuilder是非线程安全的?,包括了如何理解Java中的StringBuffer是线程安全的而StringBuilder是非线程安全的?的使用技巧和注意事项,需要的朋友参考一下 StringBuffer(线程安全) StringBuffer是线程安全的,这意味着它们具有同步方法来控制访问,因此一次只有一个线程可以