迭代连接时出现ConcurrentModificationException

时间:2015-06-28 17:50:27

标签: java collections concurrentmodification

我有一个模拟神经网络的程序,完成后会通过NEAT算法进行演化。

神经网络通过连接连接神经元来工作。进化程序的一部分是跨越神经网络,基本上从每个神经网络中获取随机神经元和连接并将它们组合在一起。但是,如果连接2个不存在或已禁用的神经元需要连接,则会被禁用。如果神经元具有少于1个现有或启用的输入/输出连接,则它将被禁用。但是,当迭代神经元的连接时,我得到了ConcurrentModificationException

我对为什么感到有些困惑,我认为这是对我的误解。代码有什么问题?

错误:

Exception in thread "AWT-EventQueue-0"    java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(Unknown Source)
at java.util.ArrayList$Itr.next(Unknown Source)
at GUIDisplay$Handler.actionPerformed(GUIDisplay.java:610)
at javax.swing.AbstractButton.fireActionPerformed(Unknown Source)
at javax.swing.AbstractButton$Handler.actionPerformed(Unknown Source)
at javax.swing.DefaultButtonModel.fireActionPerformed(Unknown Source)
at javax.swing.DefaultButtonModel.setPressed(Unknown Source)
at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(Unknown Source)
at java.awt.Component.processMouseEvent(Unknown Source)
at javax.swing.JComponent.processMouseEvent(Unknown Source)
at java.awt.Component.processEvent(Unknown Source)
at java.awt.Container.processEvent(Unknown Source)
at java.awt.Component.dispatchEventImpl(Unknown Source)
at java.awt.Container.dispatchEventImpl(Unknown Source)
at java.awt.Component.dispatchEvent(Unknown Source)
at java.awt.LightweightDispatcher.retargetMouseEvent(Unknown Source)
at java.awt.LightweightDispatcher.processMouseEvent(Unknown Source)
at java.awt.LightweightDispatcher.dispatchEvent(Unknown Source)
at java.awt.Container.dispatchEventImpl(Unknown Source)
at java.awt.Window.dispatchEventImpl(Unknown Source)
at java.awt.Component.dispatchEvent(Unknown Source)
at java.awt.EventQueue.dispatchEventImpl(Unknown Source)
at java.awt.EventQueue.access$300(Unknown Source)
at java.awt.EventQueue$3.run(Unknown Source)
at java.awt.EventQueue$3.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
at java.awt.EventQueue$4.run(Unknown Source)
at java.awt.EventQueue$4.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
at java.awt.EventQueue.dispatchEvent(Unknown Source)
at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.run(Unknown Source)

GUIDisplay课程(组织并展示神经网络):

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import java.util.Set;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;

public class GUIDisplay extends JPanel {

JButton save = new JButton("Save neural network");
JButton cross = new JButton("Cross 2 neural networks");
JButton newNN = new JButton("Create new neural network");
JButton load = new JButton("Load neural network");
NeuralRegister nr = new NeuralRegister();
int lastX = 0;
boolean drag = false;

InputNeuron inputA = new InputNeuron(nr),
        inputB = new InputNeuron(nr);

OutputNeuron outputA = new OutputNeuron(nr),
        outputB = new OutputNeuron(nr);

//ArrayList<Neuron> hidden = new ArrayList<Neuron>();
//ArrayList<Connection> connections = new ArrayList<Connection>();
ArrayList<JTextField> inputs = new ArrayList<JTextField>();
Map<String,NeuralRegister> species = new HashMap<String,NeuralRegister>();

Neuron startConnection;
Neuron endConnection;

JFrame j;

public GUIDisplay (final JFrame j) {

    this.j = j;

    setLayout(null);
    save.setLocation(10, 30);
    save.setSize(newNN.getPreferredSize());
    cross.setLocation(10, 55);
    cross.setSize(newNN.getPreferredSize());
    newNN.setLocation(10, 80);
    newNN.setSize(newNN.getPreferredSize());
    load.setLocation(10, 105);
    load.setSize(newNN.getPreferredSize());
    add(save);
    add(cross);
    add(newNN);
    add(load);

    for (Neuron n : nr.getNeurons()) {

        if (n instanceof InputNeuron) {

            JTextField text = new JTextField(Double.toString(n.getOutput()));
            text.setSize(100, 25);
            inputs.add(text);

        }

    }

    /*hidden.add(new Neuron(nr));
    hidden.add(new Neuron(nr));

    Connection inA = new Connection(inputA, hidden.get(0), nr);
    Connection inB = new Connection(inputB, hidden.get(1), nr);

    Connection outA = new Connection(hidden.get(hidden.size() - 1), outputA, nr);
    Connection outB = new Connection(hidden.get(hidden.size() - 2), outputB, nr);

    for (int i = 0; i < hidden.size(); i ++) {

        if (i < hidden.size() - 1) {

            Connection newC = new Connection(hidden.get(i), hidden.get(i + 1), nr);

        }

    }*/

    calculateNeuronLocations();

    inputA.setOutput(20);
    inputB.setOutput(-20);

    //inputA.calculateOutput();
    //inputB.calculateOutput();

    Handler h = new Handler();
    addMouseListener(h);
    addMouseMotionListener(h);
    save.addActionListener(h);
    cross.addActionListener(h);
    newNN.addActionListener(h);
    load.addActionListener(h);

}

public void calculateNeuronLocations () {

    int x = 100;
    int y = 250;

    int xGap = 100;
    int yGap = 40;

    for (Neuron n : nr.getNeurons()) {

        if (n instanceof InputNeuron) {

            n.setLocation(new Point(x,y));
            y += yGap;

        }

    }

    y = 250;
    x += xGap;

    for (Neuron n : nr.getNeurons()) {

        if (!(n instanceof InputNeuron) && !(n instanceof OutputNeuron)) {

            n.setLocation(new Point(x,y));
            y += yGap;

            if (y >= 200) {

                y = 100;
                x += xGap;

            }

        }

    }

    y = 250;
    x = j.getWidth() - 100;

    for (Neuron n : nr.getNeurons()) {

        if (n instanceof OutputNeuron) {

            n.setLocation(new Point(x,y));
            y += yGap;

        }

    }

    lastX = x;

}

@Override
public void paintComponent (Graphics g) {

    super.paintComponent(g);

    g.setColor(Color.BLACK);
    g.drawString("Connections: " + nr.getConnections().size(), 10, 10);
    g.drawString("Neurons: " + nr.getNeurons().size(), 10, 20);

    g.setColor(Color.BLUE);
    g.drawString("Input", 100, 230);
    g.drawString("Output", lastX, 230);

    for (Connection c : nr.getConnections()) {

        if (c.isEnabled()) {
            g.setColor(Color.GREEN);
        } else {
            g.setColor(Color.MAGENTA);
        }

        g.drawLine((int)c.getA().getLocation().getX(),
                (int)c.getA().getLocation().getY(),
                (int)c.getB().getLocation().getX(),
                (int)c.getB().getLocation().getY());

    }

    for (Neuron n : nr.getNeurons()) {

        if (n instanceof InputNeuron || n instanceof OutputNeuron) {

            g.setColor(new Color(150,0,0));

            g.drawRect((int)n.getLocation().getX() - 2,
                    (int)n.getLocation().getY() - 2,
                    4,
                    4);

        } else {

            if (n.isEnabled()) {
                g.setColor(Color.RED);
            } else {
                g.setColor(Color.BLUE);
            }

        }

        g.drawRect((int)n.getLocation().getX() - 5,
                (int)n.getLocation().getY() - 5,
                10,
                10);
        g.setColor(Color.BLACK);
        g.drawString(n.getId() + " (" + n.getOutput() + ")",
                (int)n.getLocation().getX() - 5,
                (int)n.getLocation().getY() - 5);

    }

    int cx = 100;
    int nx = 100;
    int y = j.getHeight() - 350;
    int width = 100, height = 100;

    for (Gene ge : nr.getGenome()) {

        boolean neuron = true;
        ArrayList<String> text = new ArrayList<String>();
        int yAddon = 15;
        int yStart = 15;

        text.add("ID: " + ge.getId());
        text.add("Enabled: " + ge.isEnabled());

        if (ge instanceof Neuron) {

            g.drawRect(nx, y, width, height);
            Neuron ne = (Neuron) ge;
            String nType = "Node: ";

            if (ne instanceof InputNeuron) {

                nType += "input";

            } else if (ne instanceof OutputNeuron) {

                nType += "output";

            } else {

                nType += "hidden";

            }

            text.add(nType);
            nx += width;

        } else if (ge instanceof Connection) {

            g.drawRect(cx, y + 150, width, height);
            yStart += 150;
            Connection ce = (Connection) ge;
            text.add("Neurons: " + ce.getA().getId() + " -> " + ce.getB().getId());
            text.add("Weight: " + ce.getWeight());
            cx += width;
            neuron = false;

        }

        for (String s : text) {

            int x = (neuron) ? nx : cx;
            g.drawString(s, x + 5 - 100, y + yStart + yAddon);
            yStart += yAddon;

        }

    }

    if (drag) {

        g.setColor(new Color(0,150,0));;
        if (startConnection != null) g.drawLine((int)startConnection.getLocation().getX(),
                (int)startConnection.getLocation().getY(),
                (int)getMousePosition().getX(),
                (int)getMousePosition().getY());

    }

    Set<String> keys = species.keySet();
    int x = j.getWidth() - 100;
    int yT = 30;
    int yGap = 15;

    for (String key : keys) {

        g.drawString(key, x, yT);
        yT += yGap;

    }

}

private class Handler implements ActionListener, MouseListener, MouseMotionListener {

    @Override
    public void mouseClicked(MouseEvent arg0) {

        Neuron toAdd = new Neuron(nr);
        toAdd.setLocation(getMousePosition());
        //hidden.add(toAdd);
        repaint();
        j.repaint();

    }

    @Override
    public void mouseEntered(MouseEvent arg0) {
        // TODO Auto-generated method stub

    }

    @Override
    public void mouseExited(MouseEvent arg0) {
        // TODO Auto-generated method stub

    }

    @Override
    public void mousePressed(MouseEvent arg0) {

        for (Neuron n : nr.getNeurons()) {

            Rectangle m = new Rectangle((int)getMousePosition().getX(),
                    (int)getMousePosition().getY(),
                    1,1);
            Rectangle r = new Rectangle();
            r.setLocation((int)n.getLocation().getX() - 5, (int)n.getLocation().getY() - 5);
            r.setSize(10, 10);
            if (m.intersects(r)) {

                startConnection = n;

            }

        }

    }

    @Override
    public void mouseReleased(MouseEvent arg0) {

        if (startConnection != null) {

        if (drag) {

            boolean found = false;

            for (Neuron n : nr.getNeurons()) {

                if (n != startConnection) {

                Rectangle m = new Rectangle((int)getMousePosition().getX(),
                        (int)getMousePosition().getY(),
                        1,1);
                Rectangle r = new Rectangle();
                r.setLocation((int)n.getLocation().getX() - 5, (int)n.getLocation().getY() - 5);
                r.setSize(10, 10);
                if (m.intersects(r)) {

                    endConnection = n;
                    found = true;

                }

                }

            }

            if (found) {

                Connection c = new Connection(startConnection,endConnection,nr);
                c.transferOutput(c.getA().getOutput());

            }

            repaint();
            j.repaint();

        }

        }

        drag = false;
        startConnection = null;

    }

    @Override
    public void actionPerformed(ActionEvent e) {

        if (e.getSource() == save) {

            String name = JOptionPane.showInputDialog(null, "Enter desired name for network", "Save", JOptionPane.INFORMATION_MESSAGE);
            species.put(name, nr);
            repaint();

        } else if (e.getSource() == newNN) {

            nr = new NeuralRegister();
            InputNeuron inputA = new InputNeuron(nr),
                    inputB = new InputNeuron(nr);

            OutputNeuron outputA = new OutputNeuron(nr),
                    outputB = new OutputNeuron(nr);

            inputA.setOutput(20);
            inputB.setOutput(-20);

            calculateNeuronLocations();
            repaint();

        } else if (e.getSource() == load) {

            load();

        } else if (e.getSource() == cross) {

            String nr1Str = JOptionPane.showInputDialog(null,"Enter name of first neural network", "Cross", JOptionPane.INFORMATION_MESSAGE);
            String nr2Str = JOptionPane.showInputDialog(null,"Enter name of second neural network", "Cross", JOptionPane.INFORMATION_MESSAGE);
            NeuralRegister nr1 = species.get(nr1Str);
            NeuralRegister nr2 = species.get(nr2Str);
            NeuralRegister nrNew = new NeuralRegister();
            NeuralRegister nrAdded = new NeuralRegister();
            ArrayList<Neuron> nDone = new ArrayList<Neuron>();
            ArrayList<Connection> cDone = new ArrayList<Connection>();

            /*NeuralRegister biggestNeurons = (nr1.getNeurons().size() > nr2.getNeurons().size()) ? nr1 : nr2;
            NeuralRegister smallestNeurons = (biggestNeurons == nr1) ? nr2 : nr1;

            NeuralRegister biggestConnections = (nr1.getConnections().size() > nr2.getConnections().size()) ? nr1 : nr2;
            NeuralRegister smallestConnections = (biggestConnections == nr1) ? nr2 : nr1;
            */

            for (Neuron n : nr1.getNeurons()) {

                nrAdded.registerNeuron(n);

            }

            for (Neuron n : nr2.getNeurons()) {

                nrAdded.registerNeuron(n);

            }

            for (Connection c : nr1.getConnections()) {

                nrAdded.registerConnection(c);

            }

            for (Connection c : nr2.getConnections()) {

                nrAdded.registerConnection(c);

            }

            for (Neuron g1 : nrAdded.getNeurons()) {

                if (!nDone.contains(g1)) {

                Neuron match = null;
                ArrayList<Neuron> search = (nr1.getNeurons().contains(g1)) ? nr2.getNeurons() :  nr1.getNeurons();

                for (Neuron g2 : search) {

                    if (g1.getId() == g2.getId()) {

                        match = g2;
                        //System.out.println("Match Found " + g1.getId());
                        nDone.add(g2);

                    }

                }

                Random r = new Random();
                Neuron select = null;
                if (match != null) {

                    select = (r.nextInt(2) == 1) ? g1 : match;
                    //System.out.println("Selected " + ((select == g1) ? "NR1" : "NR2"));

                } else {

                    select = (r.nextInt(2) == 1) ? g1 : null;

                }

                nDone.add(g1);

                if (select != null) nrNew.registerNeuron(select);

                }

            }

            for (Connection c : nrAdded.getConnections()) {

                if (!cDone.contains(c)) {

                    Connection match = null;
                    ArrayList<Connection> search = (nr1.getConnections().contains(c)) ? nr2.getConnections() :  nr1.getConnections();

                    for (Connection g2 : search) {

                        if (c.getId() == g2.getId()) {

                            match = g2;
                            //System.out.println("Match Found " + g1.getId());
                            cDone.add(g2);

                        }

                    }

                    Random r = new Random();
                    Connection select = null;
                    if (match != null) {

                        select = (r.nextInt(2) == 1) ? c : match;
                        //System.out.println("Selected " + ((select == g1) ? "NR1" : "NR2"));

                    } else {

                        select = (r.nextInt(2) == 1) ? c : null;

                    }

                    cDone.add(c);

                    if (select != null) {

                    int complete = 0;

                    for (Neuron n : nrNew.getNeurons()) {

                        if (select.getA().getId() == n.getId() && n.isEnabled()) {

                            complete ++;
                            select.setA(n);

                        } else if (select.getB().getId() == n.getId() && n.isEnabled()) {

                            complete ++;
                            select.setB(n);

                        }

                    }

                    if (complete == 2) {

                        //select.setEnabled(true);
                        nrNew.registerConnection(select);

                    } else {

                        select.setEnabled(false);
                        nrNew.registerConnection(select);

                    }

                    }

                }

            }

            for (Neuron n : nrNew.getNeurons()) {

                for (Connection c : n.getInputs()) {

                    for (Connection c2 : nrNew.getConnections()) {

                        if (c.getId() != c2.getId() || !c2.isEnabled()) {

                            n.getInputs().remove(c);

                        }

                    }

                }

                //CONCURRENT MODIFICATION EXCEPTION
                for (Connection c : n.getOutputs()) {

                    for (Connection c2 : nrNew.getConnections()) {

                        if (c.getId() != c2.getId() || !c2.isEnabled()) {

                            n.getOutputs().remove(c);

                        }

                    }

                }

                if (n.getInputs().size() < 1 || n.getOutputs().size() < 1) {

                    if (!(n instanceof InputNeuron) &&
                            !(n instanceof OutputNeuron))
                        n.setEnabled(false);

                }

            }

            load(nrNew);

        }

    }

    @Override
    public void mouseDragged(MouseEvent arg0) {

        drag = true;
        repaint();

    }

    @Override
    public void mouseMoved(MouseEvent arg0) {
        // TODO Auto-generated method stub

    }

}

public void load () {

    String search = JOptionPane.showInputDialog(null,"Enter name of neural network to load", "Load", JOptionPane.INFORMATION_MESSAGE);
    load(species.get(search));
    repaint();

}

public void load (NeuralRegister nrLoad) {

    //String search = JOptionPane.showInputDialog(null,"Enter name of neural network to load", "Load", JOptionPane.INFORMATION_MESSAGE);
    nr = nrLoad;
    nr.refresh();
    repaint();

}

}

Neuron上课:

import java.awt.Point;
import java.util.ArrayList;


public class Neuron extends Gene {

double threshold = 1;
ArrayList<Connection> inputs = new ArrayList<Connection>();
ArrayList<Connection> outputs = new ArrayList<Connection>();
double output;
Point location = new Point(0,0);

public Neuron (NeuralRegister nr) {

    id = nr.registerNeuron(this);

}

public void calculateOutput () {

    double sumOfInputs = 0;
    //System.out.println("Neuron " + id + " evaluation\n----------");

    for (Connection c : inputs) {

        sumOfInputs += c.getWeight() * c.getValue();

    }

    //System.out.println("Sum of inputs = " + sumOfInputs);
    sumOfInputs += -1 * threshold;
    //System.out.println("Sum of inputs - threshold = " + sumOfInputs);
    output = 1/(1 + Math.pow(Math.E, -sumOfInputs));
    //System.out.println("Raw output = " + output);
    output = (output == 0.5) ? 0.5 : Math.round(output);
    //System.out.println("Output = " + output + "\n----------------");

    for (Connection c : outputs) {

        if (c.isEnabled()) c.transferOutput(output);

    }

}

public void addInput (Connection c) {

    inputs.add(c);

}

public void addOutput (Connection c) {

    outputs.add(c);

}

public double getOutput() {
    return output;
}

public void setOutput(double output) {
    this.output = output;
    for (Connection c : outputs) {

        c.transferOutput(output);

    }
}

public double getThreshold() {
    return threshold;
}

public void setThreshold(double threshold) {
    this.threshold = threshold;
}

public Point getLocation() {
    return location;
}

public void setLocation(Point location) {
    this.location = location;
}

public ArrayList<Connection> getInputs() {
    return inputs;
}

public void setInputs(ArrayList<Connection> inputs) {
    this.inputs = inputs;
}

public ArrayList<Connection> getOutputs() {
    return outputs;
}

public void setOutputs(ArrayList<Connection> outputs) {
    this.outputs = outputs;
}

}

Connection上课:

public class Connection extends Gene {

Neuron a;
Neuron b;
double weight = 1;
double value = 0;

public Connection (Neuron start, Neuron end, NeuralRegister nr) {

    id = nr.registerConnection(this);
    a = start;
    b = end;
    a.addOutput(this);
    b.addInput(this);

    System.out.println("New connection made between " + a.getId() + " and " + b.getId());

}

public void transferOutput (double output) {

    value = output;
    b.calculateOutput();

}

public void setWeight (double w) {

    weight = w;

}

public double getWeight () {

    return weight;

}

public double getValue() {
    return value;
}

public void setValue(double value) {
    this.value = value;
}

public Neuron getA() {
    return a;
}

public void setA(Neuron a) {
    this.a = a;
}

public Neuron getB() {
    return b;
}

public void setB(Neuron b) {
    this.b = b;
}

}

3 个答案:

答案 0 :(得分:0)

for (Connection c : n.getInputs()) {

    for (Connection c2 : nrNew.getConnections()) {

        if (c.getId() != c2.getId() || !c2.isEnabled()) {

            n.getInputs().remove(c);

        }

    }

}

//CONCURRENT MODIFICATION EXCEPTION
for (Connection c : n.getOutputs()) {

    for (Connection c2 : nrNew.getConnections()) {

        if (c.getId() != c2.getId() || !c2.isEnabled()) {

            n.getOutputs().remove(c);

        }

    }

}

在迭代整个集合并且不使用迭代器时,您从n.getInputs()n.getOutputs() Connection集合中删除。对于所有类似的问题,解决方案是相同的:获取迭代器,使用迭代器遍历集合,并且只使用迭代器删除。

答案 1 :(得分:0)

在迭代它时,不应在ArrayList中添加或删除项目。

//CONCURRENT MODIFICATION EXCEPTION
for (Connection c : n.getOutputs()) {

   for (Connection c2 : nrNew.getConnections()) {

       if (c.getId() != c2.getId() || !c2.isEnabled()) {

          n.getOutputs().remove(c);

       }

   }

}

在上面的代码中,您要删除项目。不要那样做。将它们添加到另一个List,然后在迭代结束后使用removeAll(itemsToRemove) ArrayList方法,如下所示:

List<Connection> toRemove = new ArrayList<Connection>();

for (Connection c : n.getOutputs()) {

   for (Connection c2 : nrNew.getConnections()) {

       if (c.getId() != c2.getId() || !c2.isEnabled()) {

          toRemove.add(c);

       }

   }

}
n.getOutputs().removeAll(toRemove);

答案 2 :(得分:0)

您应该防止多个线程同时迭代和删除。尝试同步该代码。

            synchronized (this){
                //CONCURRENT MODIFICATION EXCEPTION
                for (Connection c : n.getOutputs()) {
                        for (Connection c2 : nrNew.getConnections()) {
                        if (c.getId() != c2.getId() || !c2.isEnabled()) {
                            n.getOutputs().remove(c);
                        }
                    }
                }           
            }