我正在学习java中的并发编程,并为Game of Life编写模拟。
以下是我的想法:
现在,各个细分市场的共同边界将会发生争执。如果一个线程在其邻居读取了之前的值之前覆盖了边界单元的状态,则该邻居的计算将是错误的。
我有什么选择?
我的问题是,有没有其他方法可以处理边界单元格的争用,不涉及复制数据或更高效以上两个选项?可能是使用ReaderWriterLock,volatile变量还是其他同步机制?
更新:到目前为止,double buffering solution by Peter是最干净的。但我有一个问题。 由于这两个数组是共享数据而我们没有使用任何同步(同步访问或volatile变量),它是否会产生可见性问题?多个CPU可以缓存数组值并在每次迭代时只更新数组的一部分吗?然后线程将获得边界单元格的陈旧值。这可能吗?如果没有,为什么。如果是,我该如何解决?似乎是declaring two arrays volatile will not make their individual elements volatile。
答案 0 :(得分:5)
我建议有2个int [] []数组。我们称它们为A和B. A将保留所有奇数编号“ticks”的值,B将保持偶数编号的滴答。
将A初始化为初始状态。然后让你的线程松散以计算每个单元格的下一个状态,并将结果放在B中的相应单元格中。 完成所有线程后,您将在B中获得新状态。现在,使用B计算每个单元格的下一个状态,并将结果存储在A中。在任何给定时间,一个数组将只读,另一个数组只写,所以永远不会有任何争用。
优点:
缺点:
答案 1 :(得分:1)
它没有回答你的实际问题,但我的推荐是你的第一个选择...返回新值而不是让工作线程更新它们。我更进一步,让“聚合器”将工作线程的结果合并到一个新的板状态数组中,然后丢弃第一个。我的理由是它会提高逻辑的整体可读性,因为你不得不担心“全球互动”几乎没有。
话虽如此,我有点偏颇,因为我更喜欢以功能性方式编程,除非有充分的理由不这样做。
答案 2 :(得分:1)
我会尝试以下方法:
n x m
磁贴所需的存储空间为2 * (n + m - 1)
,因此通常较大的磁贴(8x8或更多)需要按比例减少缓存值的内存。
答案 3 :(得分:0)
我偶然发现java.util.concurrent.Exchanger<V>
。它充当交换点。我可以用它来交换相邻线程之间的单元状态列表。这比屏障更好,因为我只需要在相邻的工作人员之间进行同步。
答案 4 :(得分:0)
要回答有关双缓冲的缓存问题的更新,这不是问题。 CPU具有一致的缓存,并且知道何时在另一个cpu缓存中更改了数据。