2012-06-20 57 views
1

我打算創建一個實時計數器。所以一個用戶可以增加特定密鑰的計數器值。而另一個通過ajax請求獲得更新的計數值(在循環中或使用某種長輪詢方法)。我將使用一個春天控制器,它會注入服務類我可以這樣做以下,或是否有更好的辦法:在彈簧服務類的所有實例之間共享一個哈希映射實例

@Service 
public MyService{ 

//instance variable in spring injected service class, not sure if this correct 
static final Map<String, Integer> myMap; 


public void add(String key){ 
    Integer count = myMap.get(key); 
    count++; 
    myMap.put(key, count); 
} 

//accessed via ajax loop (and controller), if value changes update display 
public Integer getCount(String key){ 
    return myMap.get(key) 
} 

@PostConstruct 
public load(){ 
    myMap = new HashMap<String, Integer>(10){{//initialize}}; 
} 

編輯有幾個答案,但目前尚不清楚這是最好:同步添加方法?在另一個類(註釋存儲庫)創建地圖並注入?還有別的嗎?

回答

2

可以,但是需要注意這些問題:

  • 映射爲空,最初,但你永遠不檢查空櫃;
  • add()方法不會修改地圖中的計數器。因爲Integer是不可變的,所以您需要將計數器放回地圖中。或者你需要可變專櫃存放地圖
  • 多個線程訪問的地圖,沒有任何形式的同步,這將導致錯誤,不穩定的行爲,或例外
  • 這種策略顯然會在情況未能您的應用程序是集羣內幾個服務器之間
+0

我已經編輯了輕微probs,但什麼是解決「多個線程訪問的地圖,沒有任何形式的同步,這將導致錯誤,不穩定的行爲,或例外」 – NimChimpsky

+0

可能是最好的辦法使用ConcurrentHashMap – Subin

+0

在實際應用程序中,除了主線程可以訪問共享資源(特別是在Web應用程序中)之外,所以一個可以使用「key」鍵將對象A置入,而另一個線程將插入對象B 「鑰匙」鍵。在映射的情況下,您可以使用[java.util.concurrent.ConcurrentHashMap](http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/ConcurrentHashMap.html)來管理這些問題。 –

0

使用的ConcurrentHashMap

public void add(String key){ 
    Integer count = myMap.get(key); 
    count= count++; 
    myMap.put(key, count); 
} 
+1

這仍然是不正確的代碼。它沒有任何同步問題,但您可能有三個線程併發地調用add方法,並且僅將值增加1。 –

+0

是的你是對的。必須讓方法同步我認爲? – Subin

+0

這是一種使代碼正確的方法,前提是訪問地圖的其他方法也是同步的。但是如果這樣做了,使用ConcurrentMap與使用簡單的HashMap相比沒有任何優勢。 –

0

Integer類是不可變的。這意味着你不能對其進行修改。因此,爲了增加計數,你必須把它到地圖中你已經增加後:

public void add(String key){ 
    Integer count = myMap.get(key); 
    count++; 
    myMap.put(key, count); 
} 

,這引入了一個問題是線程安全。如果此服務類將被多個線程同時訪問,則必須確保以安全的方式訪問其數據。由於myMap正在修改,並且因爲HashMap類不是線程安全的,所以您必須使其線程安全。一種方法是使用Collections.synchronizedMap()方法。這將自動使Map實例成爲線程安全的。

@PostConstruct 
public load(){ 
    myMap = new HashMap<String, Integer>(10){{//initialize}}; 
    myMap = Collections.synchronizedMap(myMap); 
} 
+1

它會使'Map'線程安全,但非原子'add()'方法仍然不是線程安全的。 –

+0

@ nicholas.hauschild哦,是的,的確如此。您必須使'add()'方法同步,或者將其主體包裝在'synchronized(myMap)'塊中。 – Michael