JAVA Concurrency - 等待进程完成

时间:2012-10-24 05:02:45

标签: java

我对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应该为false。它不再等待它再次成真。我认为游戏线程可能在调用另一个句柄(移动)之前没有机会设置allowMoves。我将volatile添加到allowMoves,并确保游戏线程上的函数设置为synchronized。但问题仍然存在。

这些在我的游戏课程中:

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;
}

正如我所说,我是新手,并且可能比我自己领先一点(按照惯例,但是我的风格是跳到深层,无论如何都很适合快速学习曲线。)

为你的帮助干杯。

3 个答案:

答案 0 :(得分:1)

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

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

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

public boolean getAllowMoves() {
    return allowMoves;
}

答案 1 :(得分:1)

不确定这是否有帮助,但如果您使用AtomicBoolean代替synchronizedvolatile会怎样?它说它是lock-free and thread-safe

答案 2 :(得分:0)

有专门用于资源管理的原语 - Semaphore

你需要

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

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