2012-12-28 32 views
3

所以,我很快就會有這個項目,恐怕我不太理解線程同步的概念。其實,我似乎無法得到它,所以如果我的問題是愚蠢的 - 我提前道歉。這個想法很簡單 - 我有多個線程表示動物(羚羊,獅子等擴展動物實現Runnable),以及一個二維數組Tile對象。動物需要移動而沒有碰撞 - 如果有人想移動到另一個站立的地方,它應該與它互動,然後 - 如果另一個沒有死 - 等待它離開。十字路口上的線程同步

所以,當一隻動物移動時,它顯然需要在目標磚上同步,以便兩個動物不能同時進入一個磚。然而,當它移動時,它顯然需要在正在站立的瓷磚上調用notify(),以便其他想要移動到那裏的動物可以醒着。

我試圖鎖定兩個,但結果是,動物在他們的軌道上停止死亡沒有明顯的原因。下面是一段代碼,一點點澄清:

void move(dir direction) 
{ 
    Integer tarX = ((direction==dir.east?(x+1):(direction==dir.west?(x-1):x))); // east->x+1/west->x-1/NS->x 
    Integer tarY = ((direction==dir.north?(y-1):(direction==dir.south?(y+1):y))); //see above 
    Animal an; 
    synchronized(TileManager.getInstance().playField[tarX][tarY]) 
    { 

      an = AnimalManager.getInstance().searchByXY(tarX, tarY); 
      while (an != null) 
      {      
       interact(an); //assume it's empty - if it isn't, it results in a death of target animal anyway     
       an = AnimalManager.getInstance().searchByXY(tarX, tarY); //possibly redundant? 
       if (an != null) { 
        try { 
         TileManager.getInstance().playField[tarX][tarY].wait(); 
        } catch (InterruptedException ex) { 
        } 
       } 
       an = AnimalManager.getInstance().searchByXY(tarX, tarY, dir.none); 
      } 
     synchronized(TileManager.getInstance().playField[x][y]) 
     { 
       int prevX = x; 
       int prevY = y; 
       x = tarX; 
       y = tarY; 
       TileManager.getInstance().playField[prevX][prevY].notify(); 
       TileManager.getInstance().playField[x][y].notify(); 
     } 
    } 
} 

是啊,這是一個爛攤子,我知道,它不工作,以及無論是。任何人有什麼想法做什麼?

+0

不要把一個同步塊放在另一個塊內(除非你別無選擇)。如果您覺得需要修改同步塊內的狀態,請退出它。 (我認爲,如果一隻動物暫時在兩個空間中,我認爲是可以的)。 –

+0

這是我試圖做的事情(除了在兩個空間中暫時放置動物 - 動物的座標存儲在其對象中,並且所有的動物都被存儲在一個單獨的集合中,而不是在瓷磚內)。然而,這裏發生的事情是,我只是爲了調用notify()而獲得(x,y)上的鎖,看起來沒有任何意義,但是如果沒有它,我無法通知動物等待那個瓦片。 –

+0

你在playField [x] [y]和playField [tarX] [tarY]中有潛在的殭屍動物可能會阻止對方。 – BevynQ

回答

0

您必須查看該解決方案的性能是否可以,但是您可以引入某種必須鎖定的'Arbiter'對象,才能同步訪問任何PlayField。

的模式將是:

private static final Object arbiter = new Object(); 

void move(dir direction) 
{ 
    ... 
    TileManager tileManager = TileManager.getInstance(); 

    synchronized(arbiter) 
    { 
    PlayField tarXtarYField = tileManager.playField[tarX][tarY]; 

    synchronized(tarXtarYField) 
    { 
     ... 

     PlayField xyField = tileManager.playField[x][y]; 
     synchronized(xyField) 
     { 
     ... 
     tileManager.playField[prevX][prevY].notify(); 
     xyField.notify(); 
     } 
    } 
    } 
} 

這種模式將幫助你避免僵局,但移動較慢的遊戲的價格,基本上是訪問打場通過arbiter對象序列化,所以只有1線程一次可以移動。

如果該領域不是太大,動物數量很少,表現可能是可以接受的。如果不是,那麼你真的必須從頭開始重寫這個程序。