2014-12-03 36 views
0

我正在编写一个简单的Top Down Shooter。玩家可以按住鼠标不断拍摄。由于没有本地的方法来检查鼠标按钮是否被按下,我实现了这个解决方案:https://stackoverflow.com/a/6828990/3716866Java - 两条线程不同步

这很好。但问题是我把每个子弹对象和每个游戏对象(敌人,玩家,桶等)放在一个链接列表中(两个列表中的一个用于对象,一个用于子弹)。当你拍摄一颗子弹时,它会被添加到LinkedList中。整个列表的每个runthrough都会通过碰撞检查。在射击2次后,游戏崩溃,并出现空指针异常。我认为问题在于,因为我使用第二个线程来实现鼠标按钮的按住,所以在另一个线程中它会检查整个列表中的子弹对象。由于我通过列表检查,而大小正在变化,它正在通过列表检查,它崩溃。但那只是我的理论。有人想知道如何让他们同步?

如果你需要更多的代码等告诉我,我会上传它。我只是不确定我应该发布什么。因此,在我收到垃圾邮件之前,我想等待您的反馈。

例外:

Exception in thread "Thread-2" java.lang.NullPointerException 
    at shooter.main.Handler.checkForCollision(Handler.java:50) 
    at shooter.main.Handler.tick(Handler.java:41) 
    at shooter.main.Game.tick(Game.java:189) 
    at shooter.main.Game.run(Game.java:290) 
    at java.lang.Thread.run(Unknown Source) 

处理类运行所有为每个对象蜱和更新方法,包括碰撞:

http://pastebin.com/mb206jug

我的MouseListener类在其他线程实现:

http://pastebin.com/LfGWa5se

我主要的游戏类,但我不认为这将是对这个问题非常重要:

http://pastebin.com/kW3UmZuD

我的游戏对象的抽象类:一个游戏对象的

http://pastebin.com/HbsdCUch

例子:

http://pastebin.com/vXCWZwtf

我的抽象弹药类:子弹

http://pastebin.com/dBnyXwgM

例子:

http://pastebin.com/XapmnsBv

怎么个拍法是这样的:

public void shoot() { 
    //play sound effect 
    // fire bullet 
    game.getHandler().addBullet(new Bullet9mm(game.getHandler().getPlayer().getX(), game.getHandler().getPlayer().getY(), game.getBulletImageManager(), game)); 
    // remove 1 bullet from magazine      
    game.getHandler().getPlayer().getCurWeapon().setMagAmmo(-1); 
} 

我希望我提供的每一个信息需要。如果你仍然需要我的代码,请告诉我。

+0

'java.util.LinkedList'是**不是**同步的,并且**不是**线程安全。 – mkobit 2014-12-03 03:40:48

+0

tempObject和tempBullet是什么类型?你在哪里声明了这些变量? – isnot2bad 2014-12-03 07:26:06

+0

如果出现异常,您应该始终发布异常堆栈跟踪。没有它,我们可以猜测你的代码中可能发生异常的地方。 – isnot2bad 2014-12-03 07:50:13

回答

1

LinkedList删除任何后续元素左移(从它们的索引中减去1)。返回从列表中移除的元素。所以,如果你正在删除它可能没有你所访问的子弹或玩家。您可以突出显示您的班级和方法签名,我自己或某人可以帮助您更好地进行设计。

+0

感谢您的报价。只是一个问题。你的意思是什么“突出你的班级和方法签名”? :) – 2014-12-03 03:39:42

+0

喜欢给你一个什么样的草图 – yadab 2014-12-03 04:58:51

+0

我编辑了帖子,现在提供了更多的代码和信息。我希望这已经足够了。 – 2014-12-03 10:31:03

1

即使没有多线程访问,您的实现也会失败,因为外部for循环没有考虑到您可能在迭代时删除对象。因此,即使由于碰撞而将对象移除,计数器s也始终增加。出于这个原因,被移除的对象的每个后继者都会在您的实现中跳过。

(说明:如果在s位置对象被删除,所有后续的对象移动一个位置前,位置乃至对象s + 1移动到位置s但是作为你的for循环增加s之后,该位置的新对象跳过)。

您应该始终赞成使用循环计数器的迭代器。它们可以安全地移除对象,并且在您想要更改集合的实现时更灵活。 (在你的情况下,迭代器提供比计数器好得多的性能,因为LinkedList上的基于索引的操作需要顺序遍历列表)。

这是有一些更多的改进,并应工作你的情况的范例:

private void checkForCollision() { 
    // use iterator instead of index based for loop 
    while (Iterator<GameObject> iter = objects.iterator(); iter.hasNext();) { 
     GameObject object = iter.next(); 
     // in case the object is the player, we can skip all collision tests 
     if (object == getPlayer()) continue; 

     // use implicit iterator instead of index based for loop 
     for (Bullet bullet : bullets) { 
      if (object.getCol().getBounds2D().intersects(bullet.getCol().getBounds2D())) { 
       iter.remove(); // remove object via iterator 
       break; // no need to check the rest => leave inner loop 
      } 
     } 
    } 
} 

注:此实现线程安全的,所以如果你的对象(无论是收藏objectsbullets或其中的任何对象)都可以被多个线程访问,无论是同步还是线程安全的集合都是必需的!

+0

Thx为你解释。这确实是我完全忽视的一点。 :) – 2014-12-03 10:10:11