【发布时间】:2011-01-20 16:50:31
【问题描述】:
我正在学习 java 并发编程,并为 Game of Life 编写模拟。
这是我的想法:
- 使用 int[][] 存储单元格的状态
- 将 int[][] 划分为 t 个段并使用 t 个工作线程
- t 线程将从其段中读取,为其段中的所有单元计算新值并更新单元。
- 完成计算后,他们会在栅栏旁等待其他工人完成计算
- 当越过障碍时,主线程将更新 UI。
- 工人继续计算下一个状态。
现在将在段的公共边界处发生争用。如果一个线程在其邻居读取之前的值之前覆盖了边界单元的状态,则邻居的计算将是错误的。
我有什么选择?
- 使用 callable 而不是 runnable 并让工作线程返回新值(而不是更新段本身)。主线程可以在越界后更新矩阵。此选项涉及将工作线程返回的结果复制到矩阵中。
- 使用两个屏障。工作线程从其邻居的段复制边界单元并在第一个屏障处等待。一旦通过了这个障碍,他们就会继续计算下一个状态并更新适当的段。然后他们在第二道屏障等待。主线程更新 UI。
我的问题是,有没有其他方法可以处理边界单元格的争用不涉及复制数据或更有效以上两个选项?可能是在使用 ReaderWriterLock、volatile 变量或其他同步机制?
更新:到目前为止,double buffering solution by Peter 是最干净的。但我有一个问题。 由于这两个数组是共享数据,而且我们没有使用任何同步(同步访问或 volatile 变量),会不会造成可见性问题?多个 CPU 是否可以缓存数组值并在每次迭代时只更新数组的一部分?然后线程将获得边界单元格的陈旧值。这可能吗?如果不是,为什么。如果是,我该如何解决?好像是declaring two arrays volatile will not make their individual elements volatile。
【问题讨论】:
-
需要考虑的是使用 AtomicInt 而不是常规 int
-
优势?这不会是过度同步吗?
-
为什么要使用int,用布尔值存储不是更合逻辑更高效吗?
-
我没有。在我当前的代码中,我使用的是 Enum[][].
标签: java multithreading synchronization conways-game-of-life java-memory-model