按值排序并发映射条目

时间:2011-05-09 21:03:07

标签: java sorting collections concurrency

有没有办法创建Map的线程安全实现来维护它按值排序的条目?我知道我可以像这样创建一个线程安全的Map

ConcurrentMap<String, Double> rankings = new ConcurrentHashMap<String, Double>();

然后我可以通过将它传递给像这样的实用程序方法来获取按值排序的条目:

public static <K, V extends Comparable<? super V>> Map<K, V> sortByValue(Map<K, V> map) {
    List<Map.Entry<K, V>> list = new LinkedList<Map.Entry<K, V>>(map.entrySet());
    Collections.sort(list, new Comparator<Map.Entry<K, V>>() {
        @Override
        public int compare(Map.Entry<K, V> o1, Map.Entry<K, V> o2) {
            return (o1.getValue()).compareTo(o2.getValue());
        }
    });

    Map<K, V> result = new LinkedHashMap<K, V>();
    for (Map.Entry<K, V> entry : list) {
        result.put(entry.getKey(), entry.getValue());
    }
    return result;
}

但我正在寻找的是一个线程安全的Map 维护按值排序的条目,这样我就不必调用上面的方法了每次插入/删除后,以保持条目按值排序。我想我正在寻找一种结合了ConcurrentHashMapLinkedHashMap的行为的实现,但尚未找到。

ConcurrentSkipListMap几乎提供了我想要的东西,但它似乎只支持按键值排序。

1 个答案:

答案 0 :(得分:2)

考虑为此构建复合数据结构。在较高的水平上,请执行以下操作。

首先,实现Map.Entry以保持键值对。该对的排序首先是按值,然后是按键。

private static class InternalEntry<K extends Comparable<K>,
                                   V extends Comparable<V>>
        implements Comparable<InternalEntry<K, V>>,
                   Map.Entry<K, V> {
    private final K _key;
    private final V _val;

    InternalEntry(K key, V val) {
        _key = key;
        _val = val;
    }

    public K getKey() {
        return _key;
    }

    public V getValue() {
        return _val;
    }

    public V setValue(V value) {
        throw new UnsupportedOperationException();
    }

    public int compareTo(InternalEntry<K, V> o) {
        int first = _val.compareTo(o._val);
        if (first != 0) {
            return first;
        }
        return _key.compareTo(o._key);
    }
}

整个条目可用作有序地图的

但该地图不支持按键有效查找价值。为此,请引入另一个映射,它将键映射到条目。

复合结构如下所示:

class OrderedByValue<K extends Comparable<K>, V extends Comparable<V>> {
    private final Map<InternalEntry<K, V>, Boolean> _ordering = 
        new TreeMap<InternalEntry<K, V>, Boolean>();

    private final Map<K, InternalEntry<K, V>> _lookup = 
        new HashMap<K, InternalEntry<K, V>>();

    public V put(K key, V val) {
        InternalEntry<K, V> entry = new InternalEntry<K, V>(key, val);
        InternalEntry<K, V> old = _lookup.put(key, entry);
        if (old == null) {
            _ordering.put(entry, Boolean.TRUE);
            return null;
        }
        _ordering.remove(old);
        _ordering.put(entry, Boolean.TRUE);
        return old.getValue();
    }

    @SuppressWarnings({"unchecked"})
    public Iterable<Map.Entry<K, V>> entrySet() {
        Iterable entries = Collections.unmodifiableSet(_ordering.keySet());
        return (Iterable<Map.Entry<K, V>>) entries;
    }
}

请注意,我没有提供所有必要的代码来实现完整的地图 - 如果您需要其他方法的帮助,请告诉我。

如果需要支持null键/值,你还需要在InternalEntry的比较实现中做一些特殊的案例代码。