我正在编写一个游戏,其中一个线程 - GameThread - 永远循环,更新我所有的精灵,渲染它们,然后再睡一段时间再做一遍 . 我还有一个定制的事件处理程序,处理按键等 .
在大多数情况下,这一切都很好 . 但是,如果在GameThread渲染时抛出一个事件,我会遇到问题 . 在极少数情况下,处理事件的处理程序可能会同时更改需要渲染的内容,从而影响GameThread渲染的结果 .
为了避免这种情况,我希望事件处理程序立即暂停GameThread,处理事件,然后恢复GameThread .
-
suspend()
/resume()
方法符合我的需求,但已被弃用 . 然而,就我而言,由于死锁的可能性很小,无论如何使用它们都是安全的吗? -
如果不是,我还有哪些其他替代品没有大量的开销?
我已经看到一个建议,即通过在要暂停的线程中设置一个标志来请求线程暂停 . 然而,在我的情况下,我不认为这是一个可行的选项,因为GameThread循环在迭代循环期间可能需要一段时间 . 在我完成循环之前,我将无法检查标志,到那时为时已晚 .
我需要立即暂停,否则用户会注意到事件处理的延迟 .
3 回答
显然,如果存在零死机会,那么它是安全的 . 但是有各种意想不到的方法可以解决僵局 . 例如,你可能碰巧在初始化一个类时暂停一个线程......这会使任何其他尝试引用该类的静态字段的线程死锁 . (这是JVM指定行为的结果 . 还有其他地方没有指定引擎盖下的锁定/同步 . 足够公平 . 它不需要......除非你正在考虑使用这些弃用的方法 . )
因此,现实情况是,确定(证明)它是否真的安全是非常困难的 . 如果你无法确定这一点,那么这是一件有潜在风险的事情 . 这就是为什么这些方法已被弃用 .
(严格来说,这不是死锁 . 死锁是线程永远无法继续的情况 . 在这种情况下,如果你可以恢复暂停的线程,其他线程就可以继续 . )
如果要同步对资源的访问,请使用ReentrantLock:
ReentrantLock sync = new ReentrantLock();
您必须将该锁定传递给您要访问共享数据的每个可运行的 .
然后,在您访问相关资源的每个位置,您将使用该共享锁对象,并获取并释放锁(即,您的关键部分):
这是java中非常标准的并发编程 . 请记住,“lock”是一种阻塞方法,因此您可能希望使用“tryLock”,它允许您尝试获取锁定,但返回一个关于您是否实际获得锁定的布尔值:
有一个版本的“tryLock”会等待一段时间,然后才会放弃尝试获取锁并返回false值 .
通常,你会做一些线程同步:
这将允许您执行您正在执行的两项操作之一:在游戏渲染线程中渲染或根据您的事件执行更改 .
您面临的问题似乎是您的渲染代码花费的时间太长,以至于您实际上无法获得平滑的体验(即,在渲染某些内容时,很多事件可能会堆积起来进行处理) . 在这种情况下,您应该使用可以快速完成并同步它们的独立部分进行渲染 .
没有任何代码我不能给你一个具体的建议,但一般来说它看起来像这样:
有了上述,要么:
您将呈现一个形状(并且所有事件处理程序将等待完成),或者
你的一些事件处理程序将会做某事(你的渲染线程将等待它完成)
您应该更深入地查看此Java跟踪:
因为还有其他解决方案,例如使用锁定对象:
或并发集合:
根据您的问题,可能更容易,最重要的是,经过严格测试的解决方案可以让您以标准方式执行某些操作,从而避免在推出自定义线程代码时可能遇到的所有陷阱 .
希望这可以帮助 .