【问题标题】:Add running thread objects in to an arraylist将正在运行的线程对象添加到数组列表中
【发布时间】:2013-04-24 12:55:18
【问题描述】:

我正在使用 java 创建一个小型坦克游戏。在该游戏中,生命包和硬币堆不时在游戏网格上的随机位置生成。它们都有有限的生命周期,并且生命周期结束后它们就会从场上消失。当它们在网格上可见时,任何坦克都可以在消失之前获得它们。我想将 lifepack 对象和 coinpile 对象的列表保存在 ArrayList 中,以便通过游戏 AI 算法访问它们。我希望使用简单的java知识将上述概念实现如下。

以下是我的 LifePack 类。CoinPile 类的行为方式类似:

public class LifePack extends Thread{
    public int healthBonus;
    public int lifetime;
    public String type;
    public Point location;
    public boolean visible;

    public LifePack(int x,int y,int lifetime){
        location=new Point(x, y);
        this.lifetime=lifetime;
        this.type="health_pack";
        this.visible=true;
        this.start();

    }

    public void run(){
        while(true){

            if(this.lifetime>0){
                try{
                    Thread.sleep(1);
                    if(lifetime%1000==0){
                        System.out.println("Life pack "+this.getId()+" will be disappeared in "+this.lifetime/1000+" s");
                    }
                    this.lifetime--;
                }
                catch(Exception ex){
                    ex.printStackTrace();
                }
            }
            else{
                this.visible=false;
                this.interrupt();
                break;
            }
        }
        System.out.println("Life pack visibility = "+this.visible);
    }


}

我想将新创建的 LifePack 对象添加到数组列表中,如下所示:

public ArrayList<LifePack> lifePacks;
lifePacks = new ArrayList<LifePack>();

lifePacks.add(new LifePack(x, y, lifeTime));

每次创建新的生命包时,我都会将该生命包对象添加到上面的数组列表中。一旦生命包的生命周期到期,我想将上述类中的“visible”布尔变量设置为“false”,以便我可以检查该变量以用于其他目的。

但我没有得到我想要的输出。我可以将正在运行的线程对象添加到上面的数组列表中并保持线程状态运行,还是我必须移动到不同的实现?如果有解决方案,请有人帮我解决这个问题。

谢谢。

【问题讨论】:

  • 您的架构总体上不是很好。您正在为每个 Lifepack 创建一个新线程,因此如果您有 1000 个 Lifepack,那么您将运行 1000 个线程。线程是有代价的(上下文切换等,pp.),你应该在这里做这件事真的没有意义。相反,使用一个游戏逻辑线程(或者可能为所有生命包使用一个指定线程)并检查每 x 毫秒你的生命包是否仍然存在并执行一些游戏逻辑。这是通常的游戏架构方法。
  • 谢谢@dirkk。其实我的java知识不是很好。我会试试你的想法。再次感谢。

标签: java multithreading arraylist


【解决方案1】:

我同意 dirkk 的观点,即你会启动太多线程。但是要回答您的问题,也许您应该考虑使用 AtomicBoolean 来显示。

http://docs.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/atomic/AtomicBoolean.html

【讨论】:

    【解决方案2】:

    据我所见,一个线程检查列表中的某些条目是否为假,其他线程将其设置为假,这需要是线程安全的

    您可以通过在更新操作期间同步列表本身来做到这一点

      synchronized(list){
           //update the needed entry to false
      }
    

    【讨论】:

    • 同步列表只是为了更新一个条目看起来是一个巨大的瓶颈。
    • @rethab 我知道。关于如何实时更新列表中的条目还有其他想法吗?
    • 如果它真的只是一个标志,那么原子变量就可以了。但正如我在帖子中所建议的,我会改变维护对象状态的总体思路。
    【解决方案3】:

    正如已经指出的,创建线程是个坏主意。特别是,一旦您的应用程序达到存在大量生命包的地步。另请注意,在构造函数中启动线程是非常糟糕的做法。如果你想使用普通线程,建议实现一个可运行的(java.lang.Runnable)。

    不过,总的来说,我强烈建议您使用 java.util.concurrent 包中提供的 Java 并发抽象:http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/package-summary.html 使用 ExecutorService 运行可调用对象 (java.util.concurrent.Callable) 允许您很容易改变线程数。

    我还会质疑您将所有生命包存储在同一个集合中并为每个生命包分配状态(可见性)的想法。我不由自主地想到了以下场景:一旦游戏运行了一段时间,你最终会得到大量的救生包,其中大部分不再使用。因此,您可能想要考虑为 lifepack 可能处于的不同状态设置不同的集合。这也将使丢弃对象变得非常容易(无需遍历集合)。假设这些集合将被多个线程访问,您希望它们是线程安全的。为此,您还可以在 java.util.concurrent 包中找到各种类型的集合。

    【讨论】:

      猜你喜欢
      • 2013-09-03
      • 2012-08-02
      • 1970-01-01
      • 2011-12-05
      • 1970-01-01
      • 2012-10-30
      • 2013-11-10
      • 2015-06-25
      • 2017-11-25
      相关资源
      最近更新 更多