1

我对 JAVA 尤其是并发性相当陌生,所以可能/希望这是一个相当直截了当的问题。

基本上从我的主线程我有这个:

public void playerTurn(Move move)
{

  // Wait until able to move
  while( !gameRoom.game.getCurrentPlayer().getAllowMove() )
  {
    try {
      Thread.sleep(200);
      trace("waiting for player to be available");
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
  }
  gameRoom.getGame().handle(move);
}

gameRoom.getGame() 在它自己的线程上。gameRoom.getGame().handle() 是同步的 gameRoom.game.getCurrentPlayer() 在 gameRoom.getGame() 的一个变量上,它在同一个线程中

调用 handle(move) 后,allowMoves 设置为 false,并在处理完移动后返回 true。

我多次调用 playerTurn()。我实际上是从 SmartFoxServer 扩展调用它,当它收到请求时,通常是快速连续的。

我的问题是,大多数时候它都有效。但是有时它会发出多个句柄(移动)调用,即使 allowMoves 应该为假。它没有等待它再次成为现实。我认为游戏线程可能在调用另一个句柄(移动)之前没有机会设置 allowMoves 。我在 allowMoves 中添加了 volatile,并确保游戏线程上的函数设置为同步。但问题仍在发生。

这些在我的游戏课上:

synchronized public void handle(Object msg)
{
  lastMessage = msg;
  notify();
} 

synchronized public Move move() throws InterruptedException
{
  while (true)
  {
   allowMoves = true;
   System.out.print(" waiting for move()...");
   wait();
   allowMoves = false;
   if (lastMessage instanceof Move)
   {
    System.out.print(" process move()...");
    Move m = (Move) lastMessage;
    return m;
   }
  }
}

public volatile boolean allowMoves;
synchronized public boolean getAllowMoves()
{
  return allowMoves;
}

正如我所说,我是新手,可能有点超前(像往常一样,但这是我跳入深渊的风格,无论如何都非常适合快速学习曲线)。

为你的帮助干杯。

4

3 回答 3

1

问题是您 synchronized在两个不同的对象上使用方法。

 gameRoom.game.getCurrentPlayer().getAllowMove()<-- This is synchronized on 
                                                    CurrentPlayer instance.
 gameRoom.getGame().handle(move)<-- This is synchronized on `gameRoom.getGame()`

这是你的问题。您不需要synchronized关键字 for,getAllowMoves因为字段是volatile作为volatile保证可见性语义的。

public boolean getAllowMoves() {
    return allowMoves;
}
于 2012-10-25T11:33:11.147 回答
1

不确定这是否会有所帮助,但是如果您将使用AtomicBoolean而不是synchronizedandvolatile怎么办?它说它是lock-free and thread-safe

于 2012-10-25T12:02:00.053 回答
0

有一个原语,专门用于资源管理 - Semaphore

你需要

  • 创建许可设置为 1 的信号量
  • 在寻找移动时使用获取
  • 移动完成后使用释放

所以你永远不会面对出现 2 个并发调用的句柄方法。

于 2012-10-25T11:50:05.563 回答