我目前正在编写一个BTree算法。 我已经实现了向其添加Numbers的功能。当我去测试时,我遇到了ConcurrentModificationException。
我研究了这个问题并发现了一些提示,主要是由于两件事:
我的代码中都没有出现这些问题,所以我完全迷失了......
我希望你们能帮助我!
“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);
}
}
例外:
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)
答案 0 :(得分:1)
阅读List.subList(int fromIndex, int toIndex)
的javadoc:
返回指定fromIndex(包含)和toIndex(不包括)之间此列表部分的视图。 (如果fromIndex和toIndex相等,则返回的列表为空。)返回的列表由此列表支持,因此返回列表中的非结构更改将反映在此列表中,反之亦然。返回的列表支持所有可选的列表操作。
[...]
如果支持列表(即此列表)以结构修改 以除了返回列表之外的任何方式,此方法返回的列表的语义将变为未定义。 (结构修改是那些改变了这个列表的大小,或以其他方式扰乱它的方式,正在进行的迭代可能会产生不正确的结果。)
如果您希望将子列表与原始列表断开连接,则需要复制该子列表:
new ArrayList<>(list.subList(from, to))