简体   繁体   English

Java ConcurrentModificationException; 单线程; 没有为每个循环

[英]Java ConcurrentModificationException; single Thread; without for each loop

I am currently programming a BTree Algorithm.我目前正在编写 BTree 算法。 I have already implemented the functionality to add Numbers to it.我已经实现了向其添加数字的功能。 As I went to test it, I ran into a ConcurrentModificationException.当我去测试它时,我遇到了 ConcurrentModificationException。

I researched the issue and found hints that it mainly is due to two things:我研究了这个问题,发现主要是由于两件事:

  1. Multiple Threads accessing the same List.多个线程访问同一个列表。
  2. Modifing the List while going through it using a for each loop.在使用 for each 循环遍历列表时修改列表。

Neither of these problems occur in my code, so I am completely lost...这些问题都没有出现在我的代码中,所以我完全迷失了......

I hope you guys can help me!我希望你们能帮助我!

Code from the "Knoten" class:来自“Knoten”类的代码:

public List<Nodes> Childnodes;
public List<Integer> Keys;

private Baum tree;
private Nodes parent;
private boolean isRoot;


public void Add(int number)
{
    int lastSmallerPosition = -1;

    for(int i = 0; i < Keys.size(); i++)
    {
        if(Keys.get(i) < number)
        {
            lastSmallerPosition = i;
        }
        else
        {
            if( Keys.size() < i + 1 && number == Keys.get(i + 1))
            {
                return; 
            }
            break;
        }
    }

    if(isLeaf())
    {
        Keys.add(lastSmallerPosition + 1, number);

        if(Keys.size() > tree.maxKeys)
        {
            if(isRoot) 
            {
                Nodes k1 = new Nodes(tree, this, false);
                Nodes k2 = new Nodes(tree, this, false);
                k1.Keys.addAll(Keys.subList(0, Keys.size()/2));
                k2.Keys.addAll(Keys.subList(Keys.size()/2 + 1, Keys.size()));
                Childnodes.add(k1);
                Childnodes.add(k2);

                int spareNumber = Keys.get(Keys.size()/2);
                Keys.clear();
                Keys.add(spareNumber);
            }
            else
            {
                if(parent.Keys.size() == tree.maxKeys)
                {
                    List<Integer> list = new ArrayList<Integer>();

                    if(parent.Childnodes.indexOf(this) == 0)
                    {

                        int index = parent.Childnodes.indexOf(this);

                        list.addAll(Keys);
                        list.add(parent.Keys.get(index));
                        list.addAll(parent.Childnodes.get(index + 1).Keys);

                        Keys.clear();
                        parent.Keys.remove(index);
                        parent.Childnodes.remove(index + 1);
                    }
                    else
                    {

                        int index = parent.Childnodes.indexOf(this) - 1; 

                        list.addAll(parent.Childnodes.get(index).Keys);
                        list.add(parent.Keys.get(index));
                        list.addAll(Keys);

                        parent.Childnodes.remove(index);
                        parent.Keys.remove(index);
                        Keys.clear();
                    }

                    int keysPerChildnode = (list.size() - tree.minKeys) / tree.minChilds;
                    int extraKeys = (list.size() - tree.minKeys) % tree.minChilds; 
                    int usedExtraKeys = 0;

                    for(int i = 0; i < tree.minKeys - 1; i ++)
                    {
                        Childnodes.add(new Nodes(tree, this, false));
                        Childnodes.get(i).Keys.addAll(
                                list.subList(i * keysPerChildnode + usedExtraKeys + i, (i + 1) * keysPerChildnode + usedExtraKeys + i));
                        if(usedExtraKeys < ExtraKeys)
                        {
                            Childnodes.get(i).Keys.add(list.get((i + 1) * keysPerChildnode + usedExtraKeys + i));
                            usedExtraKeys++;
                        }

                        Keys.add(list.get((i + 1) * keysPerChildnode + usedExtraKeys + i));
                    }

                    Childnodes.add(new Nodes(tree, this, false));
                    Childnodes.get(tree.minChilds - 1).Keys.addAll(list.subList(list.size() - keysPerChildnode, list.size()));
                }
                else
                {
                    Nodes k = new Nodes(tree,parent,false);
                    k.Keys = Keys.subList(Keys.size() / 2, Keys.size());
                    int NewParentKey  = Keys.get(Keys.size() / 2 - 1);

                    Keys = Keys.subList(0, Keys.size() / 2 - 1);

                    int index = parent.Childnodes.indexOf(this);

                    parent.Keys.add(index, NewParentKey);
                    parent.Childnodes.add(index + 1, k);
                }
            }
        }
    }
    else 
    {
        Childnodes.get(lastSmallerPosition + 1).Add(number);
    }
}

Exception:例外:

java.util.ConcurrentModificationException
    at java.util.ArrayList$SubList.checkForComodification(Unknown Source)
    at java.util.ArrayList$SubList.size(Unknown Source)
    at Baum.Knoten.Add(Knoten.java:39)
    at Baum.Knoten.Add(Knoten.java:175)
    at Baum.Baum.Add(Baum.java:31)
    at Test.BaumTest.AddTest(BaumTest.java:47)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)

Read the javadoc of List.subList(int fromIndex, int toIndex) :阅读List.subList(int fromIndex, int toIndex)的 javadoc:

Returns a view of the portion of this list between the specified fromIndex, inclusive, and toIndex, exclusive.返回此列表中指定的 fromIndex(包含)和 toIndex(不包含)之间的部分的视图 (If fromIndex and toIndex are equal, the returned list is empty.) The returned list is backed by this list , so non-structural changes in the returned list are reflected in this list, and vice-versa. (如果 fromIndex 和 toIndex 相等,则返回的列表为空。)返回的列表由此列表支持,因此返回列表中的非结构性更改会反映在此列表中,反之亦然。 The returned list supports all of the optional list operations.返回的列表支持所有可选的列表操作。

[...] [...]

The semantics of the list returned by this method become undefined if the backing list (ie, this list) is structurally modified in any way other than via the returned list.如果支持列表(即,此列表)以除通过返回列表以外的任何方式在结构上进行了修改此方法返回的列表的语义将变为未定义 (Structural modifications are those that change the size of this list, or otherwise perturb it in such a fashion that iterations in progress may yield incorrect results.) (结构修改是那些改变这个列表的大小,或者以其他方式扰乱它,以致正在进行的迭代可能会产生不正确的结果。)

You need to make a copy of the sublist, if you want it to be disconnected from the original list:如果您希望它与原始列表断开连接,则需要制作子列表的副本:

new ArrayList<>(list.subList(from, to))

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 Java在没有ConcurrentModificationException的情况下在同一循环中添加/删除 - Java add/remove at the same loop without ConcurrentModificationException 如何在没有concurrentmodificationexception的for循环中向java中的arraylist添加元素 - How to add elements to an arraylist in java inside a for loop without concurrentmodificationexception For循环中的java.util.ConcurrentModificationException - java.util.ConcurrentModificationException in For loop ConcurrentModificationException:单线程,两个不同的Hashtables - ConcurrentModificationException: single thread, two different Hashtables Java中的ConcurrentModificationException即使没有迭代 - ConcurrentModificationException in java even without iteration 多线程ArrayList上的java.util.ConcurrentModificationException - java.util.ConcurrentModificationException on ArrayList in multi thread 线程“main”java.util.ConcurrentModificationException中的异常 - Exception in thread “main” java.util.ConcurrentModificationException Android Game Loop中的java.util.ConcurrentModificationException - java.util.ConcurrentModificationException in Android Game Loop ConcurrentModificationException on java.util.Set上的for循环 - ConcurrentModificationException on for loop on java.util.Set 举例来说,“线程“ Thread-2”中的异常java.util.ConcurrentModificationException” - Ecplise, “Exception in thread ”Thread-2“ java.util.ConcurrentModificationException”
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM