2

ユーザーが接続し、名前を変更し、部屋に移動してチャットできるようにする単純なクライアント サーバー プログラムを作成しています。サーバーは、アクティブでない場合は各クライアントに定期的にハートビート信号を送信し、クライアントが応答しない場合はクライアントを削除します。

サーバーのクリーンアップをさらに強化するために、ルームが空かどうかも定期的に確認しています。空の場合は、サーバーからルームを削除して、不要なデータが蓄積されるのを防ぎます。ただし、この削除は問題を引き起こします。ルーム名をプレイヤー名とそのソケットを保持する ConcurrentHashMap にマップする ConcurrentHashMap を使用しています。次に、定期的にすべての部屋をループし、そこにプレーヤー (サイズが 0 より大きい) が含まれているかどうかを確認します。そうでない場合は、部屋を削除します。

ただし、サーバーがクリーンアップを決定したときに、ユーザーが空の部屋に参加する正確な瞬間を選択すると、これは非常に問題のある状況を示します. ConcurrentHashMap はすべての内部同期を処理するため、削除が 100% スレッド セーフになるように、この特定の状況を同期することはできません。ルームが削除されているときに、ユーザーがルームに参加する可能性があります。

この問題を解決するにはどうすればよいですか?

4

3 に答える 3

3

外側のマップは ConcurrentHashMap のままにしますが、内側のマップを ChatRoom クラスに置き換えます。1 つの部屋で予想される活動率は、そのような強力な同時マップを正当化するものではないようです。

ChatRoom クラスはスレッド セーフである必要があり、ルームが閉じられているかどうかを示す "closed" フラグが必要です。close() メソッドは、ルームのロックを使用してフラグを変更し、その後の操作を無効にする必要があります。実際には、close メソッドは、ルームが閉じられているかどうかを示すブール値を返す必要があります。部屋が空いている場合にのみ、それを閉じる必要があります。

アイドル ルーム チェッカー スレッドは、room.close() を呼び出してから、外側のマップから削除する必要があります。

于 2013-02-18T19:14:52.503 に答える
2

のような同期メソッドをルームに追加できますboolean closeIfEmpty()。成功した場合は、部屋をマップから安全に削除できます (2 引数の remove メソッドを使用)。追加コードが閉鎖された部屋に追加しようとすると、追加は失敗し、呼び出し元は新しい部屋を作成して閉鎖された部屋を置き換えます。

于 2013-02-18T19:12:58.083 に答える
0

Room ConcurrentHashMap インスタンスで削除操作と「ユーザーをルームに追加」操作の両方を同期し、ルームの「クローズ」フラグを保持することもできます。

何かのようなもの

void scanRoomAndRemove(Map room) {
 synchronized (room) { 
   // scan room, remove from parent Map if empty
   room.put("closed",new Object());
 }
}

void addPlayerToRoom(Player player,Map room) {
 synchronized(room) {
  if ( !room.containsKey("closed")) {
    // add player to room  
  } else {
    // whine here
  }
 }
}
于 2013-02-18T19:18:20.577 に答える