java - 使用我自己的对象作为 TreeMap 中的键

标签 java collections concurrency treemap sortedmap

由于 TreeMap 排序仅基于键,因此我使用自定义对象作为树形图中的键。在我看来,在这种情况下,我尊重 equals 和compareTo 之间的约定,如果两个对象相等,tecompareTo 返回 0。

对象代码下方:

public final class UserHighScore implements Comparable<UserHighScore>{

private final int userId;
private final int value;


public UserHighScore(int userId, int value) {
    this.userId = userId;
    this.value = value;
}

public int getUserId() {
    return userId;
}

public int getValue() {
    return value;
}


@Override
public boolean equals(Object obj) {
    if (obj == this) return true;
    if (!(obj instanceof UserHighScore)) {
        return false;
    }
    UserHighScore userHighScore = (UserHighScore) obj;
    return userHighScore.userId==userId;
}


@Override
public int compareTo(UserHighScore uh) {
    if(uh.getUserId()==this.getUserId()) return 0;
    if(uh.getValue()>this.getValue()) return 1;
    return -1;
}

}

下面是导致问题的方法:

如果用户 ID 相同,我想返回 0 以避免重复,所以如果我执行 map.put(userHighscore) ,它应该自动替换 map 中是否存在具有相同 userId 的另一个对象。 但是,如果用户不同,我希望他们根据他们的值进行排序。 这种方法对于一个线程来说工作得非常好,但是我的应用程序是并发的,当有多个线程时,它会向 map 添加重复项。 我的问题是高分 map ,它是一个并发Hasmap,里面包含一个树形图。

您认为我的方法有什么问题吗?

最佳答案

更新答案

更好地查看 TreeMap 的源代码 hashCode 并不是一个真正的问题。

问题就在这里

if (highScores.get(levelId)==null) {
    highScores.put(levelId,Collections.synchronizedSortedMap(new TreeMap<UserHighScore,Integer>()));
}

如果 highScoresConcurrentHashMap,则此代码也不是线程安全的。

这里是一个可能的场景

Thread 1                                    Thread 2
----------------------------------------------------------------------
highScores.get(levelId) is null
                                            highScores.get(levelId) is null
highScores.put(levelId, ...);
                                            highScores.put(levelId, ...);

从这里开始,两个线程使用 SynchronizedSortedMap 的不同实例。


上一个答案

TreeMap 不是 Map 的同步版本。

如果您在多线程环境中工作,则需要同步对 TreeMap 的访问。

TreeMap<UserHighScore> myTree = ...
...
UserHighScore userHighScore = ...
...
synchronized(myTree) {
    // Synchronize any access to myTree
    myTree.add(userHighScore);
}

但是您还需要重新定义 hashCode方法,因为您使用的是 Map:

Returns a hash code value for the object. This method is supported for the benefit of hash tables such as those provided by HashMap.

请记住按照契约(Contract)重新定义hashCode:

  • Whenever it is invoked on the same object more than once during an execution of a Java application, the hashCode method must consistently return the same integer, provided no information used in equals comparisons on the object is modified. This integer need not remain consistent from one execution of an application to another execution of the same application.
  • If two objects are equal according to the equals(Object) method, then calling the hashCode method on each of the two objects must produce the same integer result.
  • It is not required that if two objects are unequal according to the equals(java.lang.Object) method, then calling the hashCode method on each of the two objects must produce distinct integer results. However, the programmer should be aware that producing distinct integer results for unequal objects may improve the performance of hash tables.

关于java - 使用我自己的对象作为 TreeMap 中的键,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41014945/

相关文章:

java - 在不进行过多 JNI 调用的情况下使用 LWJGL

java - Android 用户界面 : activity_main. xml 和 content_main.xml

Java - 高效的集合管理

java - 列表的方法(如 remove、contains、removeAll)具有 Object 类型参数而不是通用 <T> 类型

scala - Scala 中的 TreeMap 键和迭代

java - 从另一个 java 进程调用 java 使其停止

java - 如何使用 SSH 访问停止 CRON 设置

java - Android 中的 Json 文本到 RecyclerView

concurrency - 这个webapp代码需要同步吗?

c - Squeak 和 Esterel 的其他现代免费类似物是什么?