2

我打算创建一个实时计数器。所以一个用户可以增加特定键的计数器值。而另一个通过 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}};
}

编辑有几个答案,但不清楚哪个是最好的:同步添加方法?在另一个类(带注释的存储库)中创建地图并注入它?还有什么?

4

3 回答 3

2

您可以,但需要注意这些问题:

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

使用 ConcurrentHashMap

public void add(String key){
    Integer count = myMap.get(key);
    count= count++;
    myMap.put(key, count);
}
于 2012-06-20T18:17:15.323 回答
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);
}
于 2012-06-20T18:19:03.690 回答