因此,我即将完成这个项目,恐怕我不太了解线程同步的概念。实际上,我似乎根本无法理解它,因此,如果我的问题很愚蠢,我会提前道歉。
这个想法很简单-我有多个代表动物的线程(Antilope,Lion等扩展了Animal实现Runnable),以及一个2D 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();
}
}
}
是的,我知道那是一团糟,而且效果也不佳。有人对做什么有任何想法吗?
最佳答案
您将必须查看该解决方案的性能是否可以,但是您可以引入某种“仲裁者”对象,您必须锁定该对象才能对任何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
对象序列化了对比赛 field 的访问,因此一次只能移动1个线程。如果 field 不是太大而动物的数量很少,那么性能可能是可以接受的。如果不是,那么您实际上必须从头开始重写该程序。