2016-12-07 53 views
1

由於TreeMap排序僅基於鍵,我使用自定義對象作爲樹形圖中的鍵。我已經在我看來,尊重在此情況下,equals和的compareTo之間的合同,如果兩個對象是相等的,TE的compareTo返回0使用我自己的對象作爲TreeMap中的鍵

下面對象的代碼:

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)它應該自動替換是否有另一個與地圖中的對象相同 用戶名。 但是,如果用戶不同,我希望他們根據他們的價值進行排序。 這種方法對於一個線程來說工作得很好,但是我的應用程序是併發的,並且當有更多的線程時,它會向地圖添加重複項。 我的問題是與高分區地圖,這是一個併發的地圖,它裏面包含一個樹形圖。

你看到我的方法有什麼問題嗎?

+0

如果您使用多個線程,那麼您的同步策略是什麼? – vanje

+0

您可能想要使用併發包中的映射https://docs.oracle.com/javase/tutorial/essential/concurrency/collections.html –

+0

已經這樣做了。我已經編輯了問題以顯示代碼,我正在使用concurrentHashmap – fgonzalez

回答

1

更新答案

綜觀TreeMaphashCode源較好是不是一個真正的問題。

的問題是在這裏

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

返回的哈希碼值的對象。這種方法支持散列表(如HashMap提供的散列表)。

記住要重新定義hashCode合同如下:

  • 每當它是一個Java應用程序的執行期間,在同一對象不止一次調用,hashCode方法必須一致地返回相同整數,只要修改了對象的等號比較中沒有使用的信息。該整數不需要從應用程序的一次執行到同一應用程序的另一次執行保持一致。
  • 如果兩個對象根據equals(Object)方法相等,則對這兩個對象中的每個對象調用hashCode方法必須產生相同的整數結果。
  • 根據equals(java.lang.Object)方法,如果兩個對象不相等,則不要求對兩個對象中的每個對象調用hashCode方法必須產生不同的整數結果。但是,程序員應該意識到,爲不相等的對象生成不同的整數結果可能會提高散列表的性能。
+0

我認爲hashCode重定義只需要HashMaps並設置 – fgonzalez

+0

但是treeMap使用compareTo而不是hashCode,我應該重新定義hashcode嗎? – fgonzalez

+0

@fgonzalez我編輯了我的答案,正如你所說的在這裏並不是真正的問題,hashCode函數。 –

0

在你乘坐過POJO對象哈希碼:

public int hashCode(){ 
    return (userId + "").hashCode() 

你也可以緩存的哈希碼。

private final int userId; 
private final int userIdHash; 
... 


public UserHighScore(int userId, int value) { 
    this.userId = userId; 
    userIdHash = (userId + "").hashCode(); 
... 

public int hashCode(){ 
    return userIdHash 

測試內存與散列碼調用。但應該可以緩存。