简体   繁体   English

Java中用于线程自动化的线程安全高性能矩阵状容器?

[英]Thread safe high-performance matrix-like container in Java for cellular automation?

I'm doing a cellular automatan that I'm running as an instance of a class with a specific thread provided for it. 我正在做一个蜂窝自动机,它作为具有特定线程的类的实例运行。 For the new functionality, namely adding live cells through mouse input while the simulation proceeds , I have to access the class' instance doing the simulation from the main thread, to modify its ArrayList> "world" named 2D container, that my Draw class uses to paint as a reference. 对于新功能,即在进行模拟时通过鼠标输入添加活动单元格,我必须从主线程访问进行模拟的类的实例,以修改其ArrayList>“ world”(名为2D容器),这是我的Draw类使用的容器绘画作为参考。

But ArrayList is not threadsafe and I get errors. 但是ArrayList不是线程安全的,并且出现错误。 At this point my "world" of cells is only 50x50, but I'd like to extend its size to 10000^2 or even much bigger. 在这一点上,我的“世界”只有50x50,但我想将其大小扩展到10000 ^ 2甚至更大。 (I'd use quadTrees at that magnitudes) (我将使用quadTrees这样的大小)

So my question is, what kind of container should I use, that is both threadsafe, wouldn't take all system resources at higher magnitudes, and "compatible" with the quadTree concept. 所以我的问题是,我应该使用哪种容器,既是线程安全的,也不会占用所有系统资源的较高资源,并且与quadTree概念“兼容”。

I don't know lot about multithreading, should I scrap the idea if of bothering a heavy-weight thread like this or could I maybe pause the thread for the period of evaluating the user's input?(Actually I tried that, I put the thread to sleep and tried to access the instance in the meanwhile, no success.) 我对多线程不太了解,是否应该打扰像这样的重量级线程,还是可以在评估用户输入的期间暂停该线程?(实际上我尝试过,我把线程放了进去)睡眠,同时尝试访问该实例,但没有成功。)

I've checked some threadsafe containers, their performance vary depending on if I just iterate over them or edit their properties and such. 我检查了一些线程安全的容器,它们的性能会有所不同,具体取决于我是对它们进行迭代还是编辑其属性等等。 There are just too many things to consider, I'd really appreciate if someone could show me what direction to pick, Andrew. 有太多事情要考虑,安德鲁,如果有人可以告诉我选择哪个方向,我将非常感激。

You could use a concept similar to double buffering . 您可以使用类似于双重缓冲的概念。 Therefore, have two different planes, let's call them A and B . 因此,有两个不同的平面,我们称它们为AB。 Every plane represents the entire 'world' of cells. 每架飞机代表着细胞的整个“世界”。 The UI thread is able to draw a plane on screen. UI线程能够在屏幕上绘制平面。

In the first iteration, plane B is updated by reading from plane A . 在第一次迭代中,通过从平面A读取来更新平面B。 As plane A is only read and not written, and plane B is only written, and not read, this can be done multithreaded without any locks. 由于仅读取和不写入平面A ,而仅写入和不读取平面B ,因此可以在没有任何锁的情况下进行多线程。 Just split up the planes into sections and assign every section to a different thread. 只需将平面拆分为多个部分,然后将每个部分分配给不同的线程。 This could be done dynamically by using the fork/join framework . 这可以通过使用fork / join框架动态完成。

When you'r done with the first iteration, hand over plane B to the UI thread. 完成第一次迭代后,将平面B移交给UI线程。 In the meantime, you can start the next iteration, which now reads from plane B into plane A . 同时,您可以开始下一个迭代,该迭代现在从平面B读入平面A。 Again this could be done in parallel. 同样,这可以并行进行。

In general, follow these rules: 通常,请遵循以下规则:

  • In every iteration, one plane is read-only, the other one is write-only 在每次迭代中,一个平面是只读的,另一平面是只写的
  • The UI thread always refers to the read-only plane for redrawing. UI线程始终引用只读平面进行重绘。
  • The cell update threads have seperate, non-overlapping sections for reading and writing. 单元更新线程具有用于读取和写入的单独的,不重叠的部分。
  • The only synchronization is at the end of every iteration when the planes are switched. 切换平面时,唯一的同步是在每次迭代的末尾。

Java has excellent concurrency tools for these things like ForkJoinPool , Exchanger , CyclicBarrier etc. Java具有出色的并发工具,可用于ForkJoinPoolExchangerCyclicBarrier等这些事情。

The write-only plane could maintain one or multiple dirty-regions, so that the UI thread does not have to update the entire UI all the times. 只写平面可以维护一个或多个脏区,因此UI线程不必始终更新整个UI。 But be smart - a dirty-region might be a bottleneck as all threads have to synchronize on it! 但是要聪明-脏区可能是瓶颈,因为所有线程都必须在其上同步!

If you have just the two threads, and your automaton thread can be written to relinquish access to critical section periodically, then you might want to consider a re-entrant lock: 如果只有两个线程,并且可以编写自动机线程来定期放弃对关键部分的访问,那么您可能需要考虑重新进入锁:
http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/locks/ReentrantLock.html http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/locks/ReentrantLock.html

Its semantics are straightforward and it works best when there are a small number of threads involved. 它的语义很简单,并且在涉及少量线程的情况下效果最佳。

Assuming that the cells themselves are created and added to the matrix only once, during start-up; 假设在启动期间仅创建一次单元并将它们添加到矩阵中; the problem is not with the ArrayList, but with the cells. 问题不在于ArrayList,而是单元格。 This is because reading from an ArrayList is thread safe, regardless of the number of reading threads; 这是因为从ArrayList进行读取是线程安全的,而不管读取线程的数量如何。 what's not thread safe is writing to a cell's fields while another thread is reading them. 不是线程安全的是在另一个线程读取它们的同时写入单元格的字段。

In that case, I suggest simply using synchronized methods for the cells themselves, with synchronization on the cell itself. 在这种情况下,我建议仅对单元格本身使用同步方法,并对单元格本身进行同步。 That way, only one thread will be able to access a cell's fields at any one time. 这样,任何时候只有一个线程将能够访问单元的字段。 There's no need to synchronize each and every method, only those that read and write to fields accessed by both threads. 无需同步每个方法,只需同步那些对两个线程访问的字段进行读写的方法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM