【发布时间】:2016-05-01 10:04:58
【问题描述】:
我有一个复杂的对象,我们称之为World,其中包含其他带有玩家数据的对象、描述世界地图的对象等。它用于回合制游戏,我在屏幕上渲染World,但使用单独的线程每轮更新World,因为这需要几秒钟才能运行。在渲染线程中运行它只会冻结屏幕。
这是World 在非渲染线程中更新并传递回渲染线程的方式:
// copy the world that is used for rendering
World world;
synchronized (Renderer.this.sync) {
world = Renderer.this.world;
}
World clone = Util.clone(world);
// update the world
Updater.update(clone);
// pass the updated world back to the render thread
SwingUtilities.invokeLater(new Runnable() {
public void run() {
synchronized (Renderer.this.sync) {
Renderer.this.world = clone;
}
}
});
这是渲染的工作原理:
// member variable: our sync-object
public final Object sync = new Object();
// member variable for world
public World world;
public void render() {
... renders the world object...
}
这是我的问题:
- 这是否正确地将新世界对象传递回渲染线程?我很确定对新克隆世界的引用是正确的,但是那个克隆世界的内容是否也与世界对象同步?
- 应该使用“volatile”以及如何使用?
- 例如
world.getPlayer(index).getName()是否正确同步?
不确定问题是否清楚?我会根据需要澄清。 - 谢谢!
【问题讨论】:
-
代码不足:
runInRenderThread()是什么?语法有点奇怪——看起来像是方法调用和匿名类实例化的交叉。渲染器线程如何工作?它是某种基于事件的无限循环还是什么?它是直接与成员字段一起使用,还是也使用synchronized块复制引用? -
它是 OpenGL 但它的工作方式与
SwingUtilities.invokeLater(...)相同。基本上回传是在渲染线程中调用的。我更新了这个例子。虽然它不是 Swing,但它的工作方式相同。 -
如果你要对整个
World进行深度复制,我建议让World(以及其中包含的所有内容)不可变。这为您省去了很多关于同步的麻烦,您只需担心安全地发布(并获取)您的World引用。 -
我要做的另一件事是将所有有关将
World移交给它自己的单独类的逻辑,这将使代码更具可读性和可测试性。 -
SwingUtilities.invokeLater()接受Runnable作为其参数。你之前的东西没有参数,但是在参数之后有一个奇怪的{}部分(而不是通常的逗号),这让我感到困惑。
标签: java synchronized volatile