JAVA Comparator抛出错误(多线程执行)

时间:2015-08-28 12:36:19

标签: java multithreading comparator agents-jade

我一直试图解决这个问题,但是没有设法做到这一点。

简而言之,我编写了一个蜜蜂蜂巢算法,其中一个预先设定的方法是按照距离块排序的点的距离对点块进行排序。

此排列使用比较器

public class PointDistanceComparator implements Comparator {

    @Override
    public int compare(Object arg0, Object arg1) {
        double resultDouble = ((Point) arg1).getSortUsageDistance()-((Point) arg0).getSortUsageDistance(); 
        if(resultDouble>0){
            return 1;
        }
        else if(resultDouble==0){
            return 0;
        }
        else{
            return -1;
        }
    }

}

我为块中的每个点计算到前一点的距离:

List<Point> pointsVector = new ArrayList<Point>();
double distance = 0;
Point point2 = pointsToVisit.get(visitedPoints.get(visitedPointsPossibleInputStartingIndex));
for(int k = visitedPointsPossibleInputStartingIndex+1; k < visitedPointsPossibleInputEndingIndex; k++){
    Point point = pointsToVisit.get(visitedPoints.get(k));
    distance = Utils.getDistanceKm(point2, point);
    point.setSortUsageDistance(distance);
    pointsVector.add(point);
}

我试着对它进行排序:

try{
    PointDistanceComparator pdComparator = new PointDistanceComparator();
    pointsVector.sort(pdComparator);
    int pointsVectorIndex = 0;
    for(int k = visitedPointsPossibleInputStartingIndex+1; k < visitedPointsPossibleInputEndingIndex; k++){
        visitedPoints.set(k, pointsVector.get(pointsVectorIndex).getIndex());
        pointsVectorIndex++;
    }
}
catch(Exception e){
    System.out.println("Unsortable route: ");
    for(Point point : pointsVector){
        System.out.println(point.getSortUsageDistance());
    }
    e.printStackTrace();
}

我得到的结果(得分很高)是:

Unsortable route: 
2.409437209114269
4.195074884990501
0.9691536825922977
1.1818593906071124
3.7959341231055044
1.344833460712328
2.7808472396551256
2.3341362332820377
3.0826195327369685
5.981871507031457
4.096491609253349
2.6730445628945447
3.6026805136626736
5.070192970603796
6.525798962460061
2.437658869598336
2.3249264696009666
2.22717482314044
1.3205919751367337
1.4326093612218957
5.032187900596256
2.6186056819000028
3.715867402052429
2.905908208286016
1.25868451375791
1.5362377319604628
3.4961506217046376
2.961495413336175
1.9345437912998407
4.49333274460376
3.2997943500252442
4.5252963191878175
5.336224710120464

甚至excel也可以很好地排序(需要交换。)。

堆栈追踪:

java.lang.IllegalArgumentException: Comparison method violates its general contract!
    at java.util.TimSort.mergeHi(Unknown Source)
    at java.util.TimSort.mergeAt(Unknown Source)
    at java.util.TimSort.mergeCollapse(Unknown Source)
    at java.util.TimSort.sort(Unknown Source)
    at java.util.Arrays.sort(Unknown Source)
    at java.util.ArrayList.sort(Unknown Source)
    at beeAlgorithm.BeeHive.sortBlockByDistanceToPrecedingPoint(BeeHive.java:334)
    at beeAlgorithm.BeeHive.permuteRoute(BeeHive.java:172)
    at beeAlgorithm.BeeHive.searchRouteNeighbourhood(BeeHive.java:144)
    at beeAlgorithm.BeeHive.iterateOverRoute(BeeHive.java:130)
    at beeAlgorithm.BeeHive.iterateOverAllRoutes(BeeHive.java:123)
    at beeAlgorithmAgents.BeeHiveAgent$1.action(BeeHiveAgent.java:114)
    at jade.core.behaviours.Behaviour.actionWrapper(Behaviour.java:344)
    at jade.core.Agent$ActiveLifeCycle.execute(Agent.java:1552)
    at jade.core.Agent.run(Agent.java:1491)
    at java.lang.Thread.run(Unknown Source)

这是在多线程环境(JADE代理)上运行的。

似乎我的比较方法有一个漏洞,但我无法找到它。有线索吗?

编辑(修复):

似乎生成点数列表就是问题所在。我不知道为什么它不能合作:

    List<Point> points = new ArrayList<Point>();
    for(int l = 0; l < algInputParameters.getPointsAmount(); l++){
        Point point = null;
        if(l == 0){
            point = new Point(0, 24*1024, 0, 0, 0, 0, 0);
            if(algInputParameters.isCityCiechanow()){
                point.generatePositionForCiechanow(random);
            }
            else if(algInputParameters.isCityTorun()){
                point.generatePositionForTorun(random);
            }
            else{
                point.generatePositionForWarsaw(random);
            }
        }
        else{
            point = new Point(0, 0, l, visitTime, 0, 0, 0);
            point.generateHours(random, startHour, endHour, duration);
            if(algInputParameters.isCityCiechanow()){
                point.generatePositionForCiechanow(random);
            }
            else if(algInputParameters.isCityTorun()){
                point.generatePositionForTorun(random);
            }
            else{
                point.generatePositionForWarsaw(random);
            }
        }
        points.add(point);
    }

但与之合作:

    List<Point> points = new ArrayList<Point>();
    for(int l = 0; l <algInputParameters.getBeeAmount(); l++){
        if(l == 0){
            Point point = new Point(0, 24*1024, 0, 0, 0, 0, 0);
            if(algInputParameters.isCityCiechanow()){
                point.generatePositionForCiechanow(random);
            }
            else if(algInputParameters.isCityTorun()){
                point.generatePositionForTorun(random);
            }
            else if(algInputParameters.isCityWarszawa()){
                point.generatePositionForWarsaw(random);
            }
            points.add(point);
        }
        else{
            Point point = new Point(0, 0, l, visitTime, 0, 0, 0);
            point.generateHours(random, startHour, endHour, duration);
            if(algInputParameters.isCityCiechanow()){
                point.generatePositionForCiechanow(random);
            }
            else if(algInputParameters.isCityTorun()){
                point.generatePositionForTorun(random);
            }
            else if(algInputParameters.isCityWarszawa()){
                point.generatePositionForWarsaw(random);
            }
            points.add(point);
        }
    }

老实说,没有一个想法。创建Points池时没有并发性,但即使Point保持为&#34; null&#34;,我也会更早得到空指针异常。也许有些人会遇到同样的问题,只要把它留在这里。

接受BigDecimal使用的答案,因为它最有可能回答任何可能的未来搜索

1 个答案:

答案 0 :(得分:1)

来自java.util.Comparator的Javadoc,比较器的一般合同如下:

  

紧跟比较合同后,商是S上的等价关系,强制排序是S上的总顺序。当我们说c对S施加的顺序与等于一致时,我们意味着排序的商是由对象定义的等价关系。 equals(Object)方法

表示如果x.compare(y) == 0则必须为x.equals(y) == true

从您的比较器看,您执行double数据类型减法并将该值与0进行比较,而已知其精度有限的两倍弱点。双重数学运算会导致精度损失,使得两个似乎等于的双重实际上并非如此。这个link完全显示了我的意思。

另一个好的摘录如下,

System.out.println( 0.1f + 0.1f + 0.1f + 0.1f + 0.1f + 0.1f + 0.1f + 0.1f + 0.1f + 0.1f );
System.out.println( 0.1d + 0.1d + 0.1d + 0.1d + 0.1d + 0.1d + 0.1d + 0.1d + 0.1d + 0.1d );

1.0000001
0.9999999999999999

添加0.1十次,您期望精确为1(一)。但你不是。

我建议您在需要进行适当比较时使用BigDecimal