どのように私のコンパレータ方式は、その一般的な契約に違反していますか?

非常に簡単、考える必要のない :

サードパーティのパッケージ

import java.util.Collections;
import java.util.Comparator;
import org.joda.time.DateTime;

私のコンパレータ

public static Comparator<Task> TASK_PRIORITY = new Comparator<Task>() {
    public int compare(Task task1, Task task2) {
        if (task1 == null && task2 == null) return 0;
        if (task1 == null) return +1; //null last
        if (task2 == null) return -1; //null last

        // Only consider retries after a task is retried 5+ times
        if (task1.getRetries() >= 5 || task2.getRetries() >= 5) {
            // Primary sort: retry count (ascending)
            int retriesCompare = Integer.compare(task1.getRetries(), task2.getRetries());
            if (retriesCompare != 0) return retriesCompare;
        }

        // Secondary sort: creation time (ascending, null first)
        int creationCompare = compareTimeNullFirst(task1.getCreationTime(), task2.getCreationTime());
        if (creationCompare != 0) return creationCompare;

        // Tertiary sort: load time (ascending, null last)
        int loadCompare = compareTimeNullLast(task1.getLoadTime(), task2.getLoadTime());
        if (loadCompare != 0) return loadCompare;

        return 0;
    }
};

private static int compareTimeNullLast(DateTime time1, DateTime time2) {
    if (time1 == null && time2 == null) return 0;
    if (time1 == null) return +1;
    if (time2 == null) return -1;
    if (time1.isBefore(time2) return -1;
    if (time1.isAfter(time2)) return +1;
    return 0;
}

private static int compareTimeNullFirst(DateTime time1, DateTime time2) {
    if (time1 == null && time2 == null) return 0;
    if (time1 == null) return -1;
    if (time2 == null) return +1;
    if (time1.isBefore(time2) return -1;
    if (time1.isAfter(time2)) return +1;
    return 0;
}

私のコンパレータを使用して

//tasks is a List<Task>
Collections.sort(tasks, TASK_PRIORITY);

私の問題

私は時々得るIllegalArgumentExceptionためにComparison method violates its general contract!私は一貫してこの例外は、十分な長さを実行しているライブデータで投げ得ることができますが、私は、問題の実際の原因を修正するかどうかはわかりません。

私の質問

私のコンパレータと間違っては何ですか?(具体的には、その契約の一部私は、違反のですか?)私は例外を覆うことなく、それを修正する方法を教えてください。

ノート

  • 私は、Java 7を使用していますし、主要なリライトせずにアップグレードすることはできません。
  • 私は、おそらく設定することにより、例外をアップカバーできるjava.util.Arrays.useLegacyMergeSortまでtrue、それは望ましい解決策ではありません。
  • 私は、ランダムデータを生成し、それぞれを検証するためのテストを作成しようとした契約条件を私は、例外がスローされるように取得することができませんでした。
  • 私は、再試行の比較を中心に条件を削除しようとしたが、私はまだ最終的に例外を得ました。
  • この行は、例外がスローされます。 Collections.sort(tasks, TASK_PRIORITY);
スティーブンC:

私たちが最初に始めましょう。あなたのコードの私の読書はあなたのコンパレータのロジックが健全であるということです。(私はnullを持つ避けているだろうTaskDateTimeの値を、それはあなたの問題には関係ありません。)

場合は、この例外が発生することができ、他の事があるcompareので、この方法は矛盾する結果を与えているTaskオブジェクトが変更されています。それがために意味的に意味があるように確かに、それは変更に(少なくとも)の再試行回数を探します。変化している他のスレッドがある場合はTask、現在のスレッドがソートされている間...発注を行うことができるフィールドを...それができましたIllegalArgumentException

(比較契約の一部は、あなたがコレクションを並べ替えている間にそのペアごとの順序は変更されませんです。)

その後、これを言います:

私が使用してImmutableSet.copyOfソートする前にリストをコピーするために、そして私がで読み取りロックの下でそれを行いますjava.util.concurrent.locks.ReadWriteLock

コレクションをコピーすると、コレクションの要素のコピーを作成しません。これは浅いコピーです。だから、同じオブジェクトを含む2つのコレクションとなってしまいます。他のスレッドが突然変異(再試行回数を増やすことにより、例えば)オブジェクトのいずれかは、そのオブジェクトの順序を変更することができれば。

ロックを使用すると、一貫性のあるコピーを持っていることを確認しますが、それは問題が何であるかではありません。

解決策は何ですか?私は、カップルを考えることができます。

  1. あなたがコピーしてソートしながら、コレクションや要素オブジェクトに対するすべての更新をブロックするために何かをロックすることができます。

  2. あなたは、収集をディープコピーできます。すなわち、元のコレクションの要素のコピーを含む新しいコレクションを作成します。

  3. あなたはのフィールドのスナップショットが含まれている軽量のオブジェクト作成できTask仕分けに関連するオブジェクトを。例えば

    public class Key implements Comparable<Key> {
        private int retries;
        private DateTime creation;
        private DateTime load;
        private Task task;
    
        public Key(Task task) {
            this.task = task;
            this.retries = task.getRetryCount();
            ...
        }
    
        public int compareTo(Key other) {
            // compare using retries, creation, load
        }
    }
    

    これは、あなたがより少ない情報をコピーしているという潜在的な利点を持っている、とあなたはの分別回収から行くことができますKey元にオブジェクトTaskのオブジェクト。

これらの選択肢のすべては、あなたが現在何をしているかよりも遅いです注意してください。私はこれを回避する方法があるとは思いません。

おすすめ

転載: http://43.154.161.224:23101/article/api/json?id=279547&siteId=1
おすすめ