我正在做一个单元格自动机,我作为一个类的实例运行,并为其提供了特定的线程。对于新功能,即在模拟过程中通过鼠标输入添加活细胞,我必须访问班级'实例从主线程做模拟,修改其ArrayList> "世界"命名为2D容器,我的Draw类用它作为参考。
但ArrayList不是线程安全的,我得到错误。在这一点上,我的世界"细胞只有50x50,但我希望将它的大小扩大到10000 ^ 2甚至更大。 (我在这个数量上使用quadTrees)
所以我的问题是,我应该使用什么样的容器,既线程安全,又不会占用更高的所有系统资源,并且"兼容"使用quadTree概念。
我对多线程知之甚少,如果打扰像这样的重量级线程,我是否应该废弃这个想法,还是可以在评估用户输入的时候暂停线程?(实际上我试过了,我让线程进入睡眠状态,同时尝试访问该实例,但没有成功。)
我检查了一些线程安全容器,它们的性能取决于我是否只是迭代它们或编辑它们的属性等。有太多事情需要考虑,如果有人能告诉我选择的方向,我真的很感激, 安德鲁。
答案 0 :(得分:1)
您可以使用类似于double buffering的概念。因此,有两个不同的平面,我们称之为 A 和 B 。每架飞机都代表着整个“世界”。细胞UI线程能够在屏幕上绘制平面。
在第一次迭代中,通过从平面 A 读取来更新平面 B 。由于平面 A 仅被读取而未被写入,并且平面 B 仅被写入且未被读取,因此可以在没有任何锁定的情况下完成多线程。只需将平面拆分为多个部分,并将每个部分分配给不同的线程。这可以使用fork/join framework动态完成。
当您完成第一次迭代时,将平面 B 移交给UI线程。与此同时,您可以开始下一次迭代,现在从平面 B 读取到平面 A 。同样,这可以并行完成。
一般来说,请遵循以下规则:
Java为ForkJoinPool
,Exchanger
,CyclicBarrier
等提供了出色的并发工具。
只写平面可以维护一个或多个脏区域,因此UI线程不必一直更新整个UI。但要聪明一点 - 脏区可能是瓶颈,因为所有线程都必须同步它!
答案 1 :(得分:0)
如果您只有两个线程,并且可以编写自动机线程以定期放弃对关键部分的访问,那么您可能需要考虑重入锁定:
http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/locks/ReentrantLock.html
它的语义很简单,当涉及少量线程时,它的效果最好。
答案 2 :(得分:0)
假设在启动期间创建了单元格本身并仅将其添加到矩阵中一次;问题不在于ArrayList,而在于细胞。这是因为无论读取线程的数量如何,来自ArrayList的读取都是线程安全的。什么不是线程安全的写到单元格的字段,而另一个线程读取它们。
在这种情况下,我建议只对细胞本身使用synchronized方法,并在细胞本身上进行同步。这样,任何时候只有一个线程能够访问一个单元的字段。不需要同步每个方法,只需要读取和写入两个线程访问的字段。