【问题标题】:Synchronizing a passed ArrayList同步传递的 ArrayList
【发布时间】:2017-05-24 19:18:14
【问题描述】:

我有一个项目,其中包含一些 JFrame 和小点移动和模拟生物。这些应该是可以繁殖和死亡的,所以我需要修改所有生物的ArrayList。

我阅读了一些关于同步的内容,但我并没有真正了解以下内容: 我知道您可以在创建同步方法或变量时创建它们。 ArrayList 在单独的 JFrame 中创建并传递给“World”类。

有一个类“Actions”处理所有的动作,如死亡和复制,我也通过ArrayList在那里修改。

还有一个名为“Toolkit”的类,它处理生成诸如起始人口等的东西。“World”包含一个线程来重新绘制生物并使它们移动每个刻度。

此外,还有一个“Paint”类,它处理图形内容并扩展另一个 JFrame 用于显示 Graphic.drawStrings,该类还获取 ArrayList 以显示死去的生物。

那么我必须如何以及在哪里创建同步以在滴答声进行时更改列表? 这些类又大又乱,如果您要求代码,我将使用其中的指定代码更新我的问题。 感谢您的帮助^^

简化示例:

工具包:

public static ArrayList<Creature> generateCreatures() {
    int amount_creatures = 10;
    ArrayList<Creature> all = new ArrayList<>();
        for(int i = 0; i < amount_creatures; i++) {
            Creature creature = new Creature(id, sex, age, energy);
            all.add(creature);
        }
    }
    return all;

世界:

public World(ArrayList<Creature> all ...) {
    this.all = all;
        ...
    startAnimation();
} 
private void startAnimation() {
        Toolkit.progress("Start Animation");
        startDrawThread();
        new Thread() {
            public void run() {
                Toolkit.step("Animation Thread started");
                try {
                    int warten;
                    long last = System.currentTimeMillis(), latest;
                    int ticks_ps = World.this.ticks_ps;
                    Toolkit.step("Ticks PS : " + ticks_ps);
                    float millsStepInterval = 1000f / ticks_ps;
                    int i = 1;

                    actions = new Actions(paint, World.this);

                    for (steps = 0; steps < Integer.MAX_VALUE - ticks_ps && running; steps++) {

                        nextTick();

                        latest = System.currentTimeMillis();
                        warten = Math.max(Math.round(millsStepInterval * i + (last - latest)), 0);

                        if (i == ACCURACY) {
                            i = 1;
                            last = latest + warten;
                        } else
                            i++;
                        Thread.sleep(warten);

                        synchronized (World.this) {
                            if (ticks_ps != World.this.ticks_ps) {
                                ticks_ps = World.this.ticks_ps;
                                millsStepInterval = 1000f / ticks_ps;
                            }
                        }
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    interrupt();
                }
                Toolkit.step("Animation Thread finished");
            }
        }.start();

    }


private void nextTick() throws InterruptedException {

        for (Creature creature : all) {

            double moveratio = (double) (Math.random() * creature.getAge() / 100);


            if(moveratio < 5) {
                actions.move(all, creature, size.x, size.y);
            }
            else {
                actions.idle();
            }


            creature.setAge(creature.getAge() + 1);

            for(Creature creature1 : all) {
                for(Creature creature2 : all) {
                    if(Toolkit.isNextTo(creature1, creature2)){
                        if (creature1.getSex() != creature2.getSex()) {
                            if(creature1.getAge() > 1000 && creature2.getAge() > 1000) {
                                Creature mother = null;
                                if (creature1.getSex() == 1) {
                                    mother = creature1;
                                } else if (creature2.getSex() == 1) {
                                    mother = creature2;
                                }
                                actions.reproduce(mother, all);
                            }
                        }

                    }
                }
            }


        }

动作:

public static void reproduce(Creature creature, ArrayList<Creature> all) {
        int id = Toolkit.getID(all);
        Creature baby = new Creature(id, energy, creature.getPosition(), 2, Toolkit.generateSex(), creature.getSize());
        all.add(baby);
    }

油漆:

public Paint(World world, ArrayList<Creature> all) {
        super();
        this.world = world;
        this.all = all;
        setBackground(Color.WHITE);
        deads = new boolean[all.size()]; //<-- THIS ONE HAS TO BE UPDATED EACH TIME THE LIST CHANGES
    }

【问题讨论】:

  • 请创建一个Minimal, Complete, and Verifiable example 来描述您的问题。这比试图用文字来描述要好得多
  • 如果您还没有阅读docs.oracle.com/javase/tutorial/uiswing/concurrency,您可能还想阅读。您可能根本不需要处理显式同步。
  • 由于这是一个 Swing GUI,并且您没有提及在后台线程中完成的工作,因此这里可能几乎不需要同步任何内容,因为对 ArrayList 的所有更改都可能是在 single 线程、Swing 事件线程或 EDT(事件调度线程)中进行。这就引出了一个问题:你为什么认为你需要在这里同步?
  • 您可以使用线程安全的 Vector 而不是 ArrayList - 两者都实现了接口 List。或者您可以将 ArrayList 包装在一个强制线程安全的类中。避免信任 ArrayList 的所有接收者在其上进行同步。
  • 没有更多细节我只能建议检查 java.util.Vector。 java.util.List 的这个实现默认是同步的,所以一次只能有一个线程可以修改它。

标签: java multithreading swing arraylist


【解决方案1】:

您可以使用提供方法public static &lt;T&gt; List&lt;T&gt; synchronizedList(List&lt;T&gt; list) 的类Colections(请参阅此处的API)。您也可以使用 Vector 类,它是一个同步的 ArrayList,但这确实是老方法。但是在你做任何关于并发问题的阅读之前,以了解你是否真的需要这样做,因为同步是一种非常广泛的奢侈品。您是否有不同的线程同时更改您的列表?看看你是否真的需要它。

【讨论】:

  • 我猜是以下异常:线程“Thread-3”java.util.ConcurrentModificationException中的异常
猜你喜欢
  • 2019-03-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-01-03
  • 1970-01-01
  • 1970-01-01
  • 2011-08-27
相关资源
最近更新 更多