2

リアルタイムカウンターを作成するつもりです。したがって、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}};
}

編集いくつかの答えがありますが、どれが最良かは明確ではありません:addメソッドを同期しますか?別のクラス(注釈付きリポジトリ)にマップを作成し、それを注入しますか?他に何かありますか?

4

3 に答える 3

2

できますが、次の問題に注意する必要があります。

  • マップは最初は空ですが、null カウンターをチェックすることはありません。
  • add() メソッドは、マップ内のカウンターを変更しません。整数は不変であるため、インクリメントした後、カウンターをマップに戻す必要があります。または、マップ内に可変カウンターを保存する必要があります
  • 複数のスレッドが同期を行わずにマップにアクセスしているため、バグ、異常な動作、または例外が発生する可能性があります
  • アプリが複数のサーバー間でクラスター化されている場合、この戦略は明らかに失敗します
于 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クラスはスレッドセーフではないため、スレッドセーフにする必要があります。これを行う 1 つの方法は、メソッドを使用するCollections.synchronizedMap()ことです。これにより、自動的に Map インスタンスがスレッドセーフになります。

@PostConstruct
public load(){
  myMap = new HashMap<String, Integer>(10){{//initialize}};
  myMap = Collections.synchronizedMap(myMap);
}
于 2012-06-20T18:19:03.690 に答える