2

我在绘画方面遇到了一些严重的优化问题。我的代码示例如下所示:

BufferedImage img1;
synchronized(game.players){
    synchronized(game.monsters){
        synchronized(game.playersHealth){
            synchronized(game.monstersHealth){
                synchronized(game.overlays){
                    synchronized(game.projectiles){
                        img1 = game.drawAll();
                    }
                }
            }
        }
    }
}
game.setImage(img1);
game.repaint();

我知道这对你们大多数人来说可能看起来很可怕。问题是,我有多个包含数据(玩家、怪物等)的不同对象集,并且这段代码 ^ 在一个单独的线程上的“无限”循环中运行,该线程组织所有图像,然后告诉游戏重新画自己。我需要帮助。你们能指出我正确地做这样的事情的正确方向吗?

4

1 回答 1

1

请注意synchronized关键字:它仅用于提供对给定对象上的锁的独占访问。如果没有其他代码段尝试在同一个锁上同步,那么只有执行该特定代码段的线程才会被同步

这意味着:

  • 您的其他线程必须为操作该集合中的一个或多个元素的语句锁定这些集合中的任何一个。
  • 唯一被锁定的是集合:如果 T 在同步块之外,则持有对元素的引用的线程 T 在执行同步代码时仍然可以同时修改它到渲染线程 R。

现在,关于您的代码,一种解决方案是通过锁定单个对象来在渲染函数中下推同步。您可能在每个集合上都有一个循环,它一个一个地处理元素,或者类似的东西:这就是您可能想要进行同步工作的地方,或者可能是在元素本身内。例如,您可以将游戏逻辑与游戏渲染分开,让每个游戏实体实现两个接口:渲染和逻辑,并让渲染线程只访问渲染接口,而逻辑游戏访问逻辑接口。

通过在特定接口中分离这两个关注点,您可能能够更好地区分哪些信息被什么使用,以及哪些事情需要正确同步。

另一种解决方案,可能涉及较少的重构,包括将逻辑和渲染线程转换为生产者消费者设置:每个线程都通过实体列表工作,完成后将其推送到另一个线程队列。每个实体将在线程之间来回移动,并让线程在它们上工作,而不需要任何其他形式的同步,而不是它们各自的输入队列。

如果您对每个线程有不同的排序约束,那么除了尝试重新组合依赖组中的实体并分批处理它们(一个线程处理一个批处理,并将该批处理作为单个项目传递给另一个线程队列),即。尝试分离不相互依赖的实体。

于 2013-04-30T23:57:00.607 回答