2

我正在编写一个游戏,其中一个线程 - GameThread - 永远循环,更新我所有的精灵,渲染它们,然后在再次执行之前休眠一段时间。我还有一个定制的事件处理程序来处理按键等。

在大多数情况下,这一切都很好。但是,如果在 GameThread 渲染时引发事件,我会遇到问题。在极少数情况下,处理事件的处理程序可能会对需要渲染的内容进行并发更改,从而影响 GameThread 渲染的结果。

为了避免这种情况,我希望事件处理程序立即暂停 GameThread,处理事件,然后恢复 GameThread。

  1. suspend()/方法适合我的resume()需要,但它们已被弃用。但是,就我而言,由于死锁的可能性很小,无论如何使用它们是否安全?

  2. 如果不是,我还有哪些其他替代方案不会产生大量开销?

我看到了通过在要暂停的线程中设置标志来请求线程暂停的建议。然而,就我而言,我认为这不是一个可行的选择,因为 GameThread 循环在循环迭代期间可能需要一段时间。在我完成循环之前,我将无法检查标志,到那时为时已晚。

我需要立即暂停,否则用户会注意到事件处理的延迟。

4

3 回答 3

1

如果要同步对资源的访问,请使用 ReentrantLock:

ReentrantLock 同步 = 新的 ReentrantLock();

您必须将该锁传递给要访问共享数据的每个可运行文件。

然后在您访问相关资源的每个地方,您将使用该共享锁对象,并获取和释放锁(即,您的关键部分):

sync.lock();

try {
  // critical section code here
}
finally {
  sync.unlock();
}

这是Java中非常标准的并发编程。请记住,“lock”是一种阻塞方法,因此您可能希望使用“tryLock”来代替,它允许您尝试获取锁,但返回一个关于您是否实际获得锁的布尔值:

 if (sync.tryLock()) {
   try {
     //critical section
   }
   finally {
     sync.unlock();
   }
 }

有一个版本的“tryLock”会等待给定的时间,然后才会放弃尝试获取锁并返回错误值。

于 2012-03-31T03:14:41.403 回答
1

通常,你会做一些线程同步:

这将让您做您正在做的两件事之一:要么在游戏渲染线程中渲染,要么根据您的事件进行更改。

您面临的问题似乎是您的渲染代码花费的时间太长,以至于您实际上无法获得流畅的体验(即,在您渲染某些东西时,很多事件可能会堆积起来进行处理)。在这种情况下,您应该使用可以快速完成并在它们上同步的独立部分进行渲染。

没有任何代码我不能给你一个具体的建议,但总的来说它看起来像这样:

List<Shape> shapesToRender;
Object lockObject = new Object(); // Note this must be somehow shared between two threads

// Your rendering thread method
public void renderForever() {
  while(true) {
    for(Shape shape: shapesToRender) {
      synchronized(lockObject) {
        render(shape);
      }
    }
  }
}

// One of your event handlers
public void handleEvent(Event event) {
  synchronized(lockObject) {
    // Process event somehow, e.g. change the color of some of the shapes
    event.getShape().setColor(Color.RED);
  }
}

有了上述,要么:

  • 您将渲染一个形状(并且您的所有事件处理程序都将等待它完成),或者
  • 您的一些事件处理程序将做某事(并且您的渲染线程将等待它完成)

您应该更深入地查看这条 Java 线索:

因为还有其他解决方案,例如使用锁定对象:

或并发集合:

这取决于您的问题,可能更容易,最重要的是,经过良好测试的解决方案可以让您以标准方式做某事,从而避免在推出自定义线程代码时可能遇到的所有陷阱。

希望这可以帮助。

于 2012-03-31T03:16:34.580 回答
0

suspend() / resume() 方法适合我的需要,但它们已被弃用。但是,就我而言,由于死锁的可能性很小,无论如何使用它们是否安全?

显然,如果死锁的可能性为零,那么它是安全的。但是有各种意想不到的方法会导致僵局。例如,您可能碰巧在初始化一个类时暂停了一个线程……这会使任何其他试图引用该类的静态字段的线程死锁。(这是 JVM 特定行为的结果。还有其他地方没有指定在幕后进行的锁定/同步。很公平。它不需要......除非你正在考虑使用这些已弃用的方法。)

所以,现实是很难确定(证明)它是否真的安全。如果你不能确定这一点,那么这是一件有潜在风险的事情。这就是为什么不推荐使用这些方法的原因。

(严格来说,这不是死锁。死锁是线程永远无法继续进行的情况。在这种情况下,如果您可以恢复暂停的线程,其他线程可以继续进行。)

于 2012-03-31T03:34:41.220 回答