在spring服务类的所有实例之间共享一个hashmap实例

时间:2012-06-20 18:04:49

标签: java spring real-time

我打算创建一个实时计数器。因此,一个用户可以递增特定键的计数器值。而另一个通过ajax请求获取更新的计数值(在循环中,或使用一些长轮询方法)。我将使用一个spring控制器,它将注入服务类,我可以做下面的事情,还是有更好的方法:

@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}};
}

编辑有几个答案,但不清楚哪个是最好的:同步add方法?在另一个类(带注释的存储库)中创建映射并注入它?还有别的吗?

3 个答案:

答案 0 :(得分:2)

您可以,但需要了解这些问题:

  • 地图最初为空,但您从不检查空计数器;
  • add()方法不会修改地图中的计数器。由于Integer是不可变的,因此在递增后需要将计数器放回映射中。或者你需要在地图中存储可变计数器
  • 几个线程正在访问地图而没有任何同步,这将导致错误,不稳定行为或异常
  • 如果您的应用程序在多个服务器之间集群,这个策略显然会失败

答案 1 :(得分:0)

使用ConcurrentHashMap

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

答案 2 :(得分: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);
}