我正在使用即时模式GUI模式编写一个GUI应用程序,UI运行在一个与引擎分离的线程上,该引擎为应用程序的实际功能提供了动力。GUI线程最终会迭代引擎线程在概念上“拥有”的许多对象列表,并且这些列表很少发生变化。GUI线程是vsync‘’ed的,这意味着它在60 is左右运行,而引擎线程在200 is左右运行。
有时,UI中的操作将改变引擎中集合的内容,我有一个消息传递系统将Runnable发布到引擎线程,以执行这些更改,以确保这些突变不会与引擎中发生的情况发生冲突。这样,我就可以确保引擎始终看到数据的一致视图,这对于我的应用程序来说是非常重要的。
但是,由于引擎负责所有数据的更改,有时会发生引擎在GUI迭代时更改集合的内容的情况,而且由于这些集合是标准的ConcurrentModificationException集合,因此可以预见地正确抛出一个Java集合。我可以想出一些高层次的方法来处理这个问题:
锁定带来了很大的性能损失,虽然GUI有时在等待从引擎线程获取锁时停止运行是很好的,但是引擎线程以一致的速度运行是非常重要的,甚至R/W锁也会导致引擎线程中的阻塞。双缓冲具有显著的复杂性,因为每个帧上都有大量由GUI读取的数据。
我给出了所有这些背景,因为我知道备选方案3很难看,我的问题在某种意义上是“不正确的问题”。ConcurrentModificationException的Javadoc甚至说:
请注意,通常情况下,不能保证快速失败的行为在不同步并发修改的情况下提供任何硬的保证。快速失败的操作在最大努力的基础上将ConcurrentModificationException抛出。因此,编写一个依赖于此异常的程序是错误的: ConcurrentModificationException应该只用于检测bug。
但!我不关心单个框架的GUI是否正确,这将被CME破坏。我只关心下一帧会发生什么。这就引出了我的问题:在迭代器抛出ArrayList和HashMap之后,继续使用ConcurrentModificationException集合(我最感兴趣的是ConcurrentModificationException的答案)是否安全?这似乎是合乎逻辑的,但我找不到一段文档,说明在抛出CME之后,对象仍将处于可用状态。显然,迭代器在这一点上已经结束了,但是我想吞下异常并继续使用集合。
发布于 2019-03-21 18:25:20
对于大多数藏品来说,只要你只有一个作家,你可能会没事,但这是没有保证的。如果在一个HashMap上有多个作者,那么最终可能会有一个损坏的映射,它的结构中有一个无限循环。
我建议您使用ReentrantLock,它有一个tryLock()方法,如果您只想支持-获取-一个锁-如果-如果没有-使用的方法,以尽量减少阻塞。
另一种将数据从一个线程传送到另一个线程的方法是Queue修改任务,在其他情况下,引擎可以在不繁忙的情况下处理这些任务。这只允许通过一个线程进行所有访问。
顺便说一句:一个锁/解锁大约需要1微秒,除非你经常这么做,否则这对你不会有太大影响。
发布于 2019-03-21 18:25:10
引用部分引文:
因此,错误的编写了一个依赖于这个异常的程序,因为它的正确性: ConcurrentModificationException应该只用于检测bug。
结论:您的代码是错误的,需要修复,因此,集合处于什么状态并不重要。
您不应该在有效代码中得到该错误。这是一个永远不应被抓住并采取行动的例外。
发布于 2019-03-21 18:42:50
GUI线程在概念上由引擎线程“拥有”的许多对象列表上进行迭代。
由于引擎拥有数据,所以我认为它不应该公开地与GUI共享数据。
考虑让引擎将数据推送到GUI,而不是让GUI从引擎数据结构中提取(或直接读取)。这样,引擎就可以完全和独占地控制它的数据,就像它应该做的那样。
缺点是,这可能需要进行重大的重新设计。
但这些好处可能足以证明它的存在:
ConcurrentModificationException最后一点可能很重要,取决于您正在处理的数据数量或重绘的复杂程度。如果分析显示需要这样做,那么将更新推到GUI将为优化提供更大的灵活性。例如,您可以更好地利用GUI端的缓存,并通过引擎推送的更新使这些缓存失效。
https://stackoverflow.com/questions/55286705
复制相似问题