The ONE使用笔记:解决“Comparison method violates its general contract!”

The ONE跑MaxProp、Prophet可能会遇到“Comparison method violates its general contract!”,该问题是JDK不兼容导致的,本文给出解决方法。

1. 问题描述

The ONE跑MaxProp、Prophet可能(取决于你JDK的版本)会报“java.lang.IllegalArgumentException: Comparison method violates its general contract!”错误,导致无法仿真。

Exception in thread "main" java.lang.IllegalArgumentException: Comparison method violates its general contract!
    at java.util.TimSort.mergeLo(TimSort.java:747)
    at java.util.TimSort.mergeAt(TimSort.java:483)
    at java.util.TimSort.mergeCollapse(TimSort.java:410)
    at java.util.TimSort.sort(TimSort.java:214)
    at java.util.TimSort.sort(TimSort.java:173)
    at java.util.Arrays.sort(Arrays.java:659)
    at java.util.Collections.sort(Collections.java:217)
    at routing.MaxPropRouter.tryOtherMessages(MaxPropRouter.java:385)
    at routing.MaxPropRouter.update(MaxPropRouter.java:300)
    at core.DTNHost.update(DTNHost.java:342)
    at core.World.updateHosts(World.java:200)
    at core.World.update(World.java:171)
    at ui.DTNSimTextUI.runSim(DTNSimTextUI.java:29)
    at ui.DTNSimUI.start(DTNSimUI.java:77)
    at core.DTNSim.main(DTNSim.java:170)

2. 问题原因

产生该问题的原因是JDK1.6+要求所有比较器必须是可传递的(transitive),比如有A > BB > C,必须得保证有推出A > C(同理,对于=<也需满足传递性)。而The ONE源码是基于JDK1.6的,JDK1.6没有该要求。

3. 解决方法

解决该问题至少有3种方法。

(1)使用JDK1.6版本运行

(2)修改The ONE源码,使其满足传递性

只需要更改Router的比较器Comparator就可以了,比如MaxProp的MaxPropComparator

private class MaxPropComparator implements Comparator<Message> {
    ...
}

(3)重新编译源码

加上一些选项,重新编译The ONE源码,使其能在JDK1.6+能正常运行[1]。

方法一:在main函数第一行加入如下代码:

System.setProperty("java.util.Arrays.useLegacyMergeSort", "true");

方法2:编译时,加上选项-Djava.util.Arrays.useLegacyMergeSort=true,完整Java编译如下:

 java -Djava.util.Arrays.useLegacyMergeSort=true -d64 -Xms512m -Xmx4g -cp .:lib/ECLA.jar:lib/DTNConsoleConnection.jar core.DTNSim $*

参考资料:
[1] StackOverflow: Comparison method violates its general contract!” – TimSort and GridLayout

Leave a Reply

Your email address will not be published. Required fields are marked *