问题标签 [java-memory-model]

For questions regarding programming in ECMAScript (JavaScript/JS) and its various dialects/implementations (excluding ActionScript). Note JavaScript is NOT the same as Java! Please include all relevant tags on your question; e.g., [node.js], [jquery], [json], [reactjs], [angular], [ember.js], [vue.js], [typescript], [svelte], etc.

0 投票
3 回答
464 浏览

java - java对象结构的线程安全发布?

假设我有以下代码:

“Catalog”是一个对象结构,createCatalog() 方法和“Catalog”对象结构在编写时并没有考虑到并发性。产品目录中有几个非最终的、非易失的引用,甚至可能存在可变状态(但这必须处理)

我理解内存模型的方式,这段代码不是线程安全的。有什么简单的方法可以让它安全吗?(这个问题的广义版本实际上是关于在线程爆炸开始之前创建的共享结构的单线程构造)

0 投票
6 回答
16228 浏览

java - Java中同步的记忆效应

JSR-133 常见问题解答说:

但同步不仅仅是互斥。同步确保线程在同步块之前或期间写入的内存以可预测的方式对在同一监视器上同步的其他线程可见。退出同步块后,我们释放监视器,这具有将缓存刷新到主内存的效果,以便该线程进行的写入可以对其他线程可见。在我们进入同步块之前,我们获取了监视器,它具有使本地处理器缓存无效的效果,以便从主内存重新加载变量。然后,我们将能够看到以前版本可见的所有写入。

我还记得读过现代 Sun VM 上的非竞争同步很便宜。我对这种说法有点困惑。考虑如下代码:

对 x 的更新需要同步,但是获取锁是否也会从缓存中清除 y 的值?我无法想象会是这样,因为如果这是真的,像锁条带这样的技术可能无济于事。或者,JVM 是否可以可靠地分析代码以确保 y 不会在另一个使用相同锁的同步块中被修改,因此在进入同步块时不会将 y 的值转储到缓存中?

0 投票
4 回答
552 浏览

java - 事件调度线程符合 Java 内存模型

这与我之前提出的一个问题有关,答案是:

如果一个字段被多个线程访问,它应该是 volatile 或 final,或者只能使用同步块访问。否则,分配的值可能对其他线程不可见。

此外,任何在屏幕上操作像素的东西都应该从事件调度线程中运行,尽管当您使用重绘/绘制时这会被透明地处理。

因此,根据我的理解,我们需要担心像精灵在屏幕上移动的动画这样简单的东西的内存模型。

我的问题是,这种理解是否正确,而 Sun 教程示例,例如TumbleItem ( source ) 不正确?

0 投票
5 回答
425 浏览

java - Java 并发问题 - 在集合上同步

以下同步代码片段是否ArrayList可以在多线程环境中工作?

我担心一个线程将无法看到另一个线程的更改。

0 投票
5 回答
4047 浏览

java - 康威人生游戏的多线程 Java 程序 - 边界单元的争用

我正在学习 Java 中的并发编程,并为 Game of Life 编写模拟。

这是我的想法:

  • 使用 int[][] 存储单元格的状态
  • 将 int[][] 划分为 t 个段并使用 t 个工作线程
  • t 线程将从它们的段中读取,计算其段中所有单元的新值并更新单元。
  • 一旦他们完成计算,他们就会在障碍处等待其他工人完成
  • 当越过障碍时,主线程将更新 UI。
  • 工人继续计算下一个状态。

现在将在段的共同边界处发生争用。如果一个线程在其邻居读取之前的值之前覆盖了边界单元的状态,则邻居的计算将是错误的。

我有哪些选择?

  • 使用 callable 而不是 runnable 并让工作线程返回新值(而不是更新段本身)。主线程可以在越界后更新矩阵。此选项涉及将工作线程返回的结果复制到矩阵中。
  • 使用两个屏障。工作线程从其邻居的段复制边界单元并在第一个屏障处等待。一旦通过了这个障碍,他们就会继续计算下一个状态并更新适当的段。然后他们在第二道屏障等待。主线程更新 UI。

我的问题是,有没有其他方法可以处理不涉及复制数据或比上述两个选项更有效的边界单元格的争用?可能是在使用 ReaderWriterLock、volatile 变量或其他同步机制?

更新:到目前为止,彼得的双缓冲解决方案是最干净的。但我有一个问题。由于这两个数组是共享数据并且我们没有使用任何同步(同步访问或 volatile 变量),它不会造成可见性问题吗?多个 CPU 是否可以缓存数组值并在每次迭代时只更新数组的一部分?然后线程将获得边界单元格的陈旧值。这可能吗?如果不是,为什么。如果是,我该如何解决?似乎声明两个数组 volatile 不会使它们的各个元素 volatile

0 投票
5 回答
9918 浏览

java - 不稳定的保证和乱序执行

重要编辑我知道两个分配发生的线程中的“之前发生”我的问题是另一个线程是否有可能在“a”仍然为空时读取“b”非空。所以我知道,如果你从与之前调用setBothNonNull(...)的线程相同的线程调用doIt() ,那么它不能抛出 NullPointerException。但是,如果从另一个线程调用doIt()而不是调用setBothNonNull(...)怎么办?

请注意,此问题仅与volatile关键字和volatile保证有关:与关键字无关(因此请不要synchronized回答“您必须使用同步”,因为我没有任何问题要解决:我只是想了解volatile保证(或缺乏保证)关于乱序执行)。

假设我们有一个包含两个volatileString 引用的对象,这些引用由构造函数初始化为 null,并且我们只有一种方法来修改这两个 String:通过调用setBoth(...)并且我们只能在之后将它们的引用设置为非空引用(仅允许构造函数将它们设置为空)。

例如(这只是一个例子,还没有问题):

setBothNoNull(...)中,分配非空参数“a”的行出现在分配非空参数“b”的行之前。

然后,如果我这样做(再一次,毫无疑问,接下来是问题):

我的理解是否正确,由于无序执行我可以获得NullPointerException

换句话说:不能保证因为我读到了一个非空的“b”,我就会读到一个非空的“a”?

因为由于无序(多)处理器和工作方式volatile“b”可以在“a”之前分配?

volatile保证在写入之后读取始终会看到最后写入的值,但是这里有一个无序的“问题”,对吗?(再一次,“问题”是故意试图理解volatile关键字和 Java 内存模型的语义,而不是解决问题)。

0 投票
3 回答
1775 浏览

scala - Scala 和 Java 内存模型

Java 内存模型(从 1.5 开始)将final字段与非final字段区别对待。特别是,如果this在构造过程中引用没有转义,final那么即使对象通过数据竞争对其他线程可用,对构造函数中字段的写入也保证在其他线程上可见。(不保证对非字段的写入final可见,因此如果您不正确地发布它们,另一个线程可能会看到它们处于部分构造的状态。)

是否有任何关于 Scala 编译器如何/是否为类创建final(而不是非final)支持字段的文档?我查看了语言规范并搜索了网络,但找不到任何明确的答案。(相比之下,@scala.volatile注释记录为将字段标记为volatile

0 投票
3 回答
583 浏览

java - Java LockSupport 内存一致性

Java 6 API 问题。调用是否与刚刚未停放的线程中的返回LockSupport.unpark(thread)发生之前的关系?LockSupport.park我强烈怀疑答案是肯定的,但 Javadoc 似乎没有明确提及。

0 投票
4 回答
17886 浏览

java - CopyOnWriteArrayList 如何是线程安全的?

我查看了OpenJDK 的源代码CopyOnWriteArrayList似乎所有的写操作都受到同一个锁的保护,而读操作根本不受保护。据我了解,在 JMM 下,对变量的所有访问(读取和写入)都应该受到锁的保护,否则可能会发生重新排序的影响。

例如,set(int, E)方法包含这些行(处于锁定状态):

get(int)另一方面,该方法只做return get(getArray(), index);

根据我对 JMM 的理解,这意味着get如果语句 1-4 像 1-2(new)-4-2(copyOf)-3 一样重新排序,则可能会观察到数组处于不一致状态。

我是否错误地理解了 JMM,或者是否有任何其他解释为什么CopyOnWriteArrayList是线程安全的?

0 投票
7 回答
459 浏览

java - 可增长的二项式系数数组的双重检查锁定

我正在尝试使用双重检查锁定来维护一个二项式系数数组,但我最近读到双重检查锁定不起作用。效率非常重要,因此除非仅在条件语句中,否则不能选择使用 volatile。我看不到将静态类与单例对象一起使用的方法(这是框架的一部分,我不知道人们需要使用该函数来处理什么样的数字,所以我无法猜测最大值是多少选择的值将是或是否将使用该函数)。我唯一能想到的就是让一切都不是静态的,并坚持需要使用此方法的每个线程都用自己的数组实例化一个选择对象。看来这应该是不必要的。