簡體   English   中英

默認情況下是否同步ConcurrentHashMap的值?

[英]Are values of ConcurrentHashMap being synchronized by default?

下面是我在這里找到的一段代碼。 它模仿一個在線游戲服務器,玩家可以在其中加入桌子。

public class GameServer {
  public Map<String, List<Player>> tables = new ConcurrentHashMap<String, List<Player>>();

  public void join(Player player, Table table) {
    if (player.getAccountBalance() > table.getLimit()) {
      List<Player> tablePlayers = tables.get(table.getId());

      synchronized (tablePlayers) {
        if (tablePlayers.size() < 9) {
          tablePlayers.add(player);
        }
      }
    }
  }

  public void leave(Player player, Table table) {/*Method body skipped for brevity*/}

  public void createTable() {
    Table table = new Table();
    tables.put(table.getId(), table);
  }

  public void destroyTable(Table table) {
    tables.remove(table.getId());
  }
}

tablePlayers是ConcurrentHashMap的值之一。

List<Player> tablePlayers = tables.get(table.getId());

既然ConcurrentHashMap已經是線程安全的,為什么要使用它時還需要同步其value對象?

  synchronized (tablePlayers) {
    ...
  }

因為在程序中使用線程安全的對象不會使程序成為線程安全的。

有問題的代碼在這里:

  synchronized (tablePlayers) {
    if (tablePlayers.size() < 9) {
      tablePlayers.add(player);
    }
  }

顯然,打算將桌子的大小限制為不超過9個玩家。

沒有synchronized就無法工作。 調用tablePlayers.add(player)時,將無法知道表的大小。 問題是,線程A可以調用tablePlayers.size() ,並獲取數字8。然后線程B可以將玩家添加到表中。 線程A可以測試8 < 9 (在我看來不錯),然后向表中添加另一個玩家。 結果是桌子上有十個玩家。 不是作者的意圖。

該表是“線程安全的”這一事實僅意味着該表自身的內部數據不會在多個線程訪問它時被破壞。 並不意味着該方案將永遠做正確的事與數據。

既然ConcurrentHashMap已經是線程安全的,為什么要使用它時還需要同步其value對象?

CHM 線程安全的,但這僅意味着它可以保護自己免受並行操作的影響。 僅僅因為您將對象存儲在CHM中並不能使該對象也具有神奇的線程安全性。 從CHM中檢索表列表后,如果要由多個線程訪問該對象,則可以適當地鎖定該對象。

就您的代碼而言,如果兩個線程同時調用join,會發生什么?

synchronized (tablePlayers) {
   // race condition here because a test...
   if (tablePlayers.size() < 9) {
      // and then the add method
      tablePlayers.add(player);
   }
}

如果沒有synchronized塊,則這兩個線程可能都同時檢查,並且看到表的大小為8(例如),然后兩個都將自己添加到表中。 這就是比賽條件的全部。 因為有2個操作(一個測試,然后附加)時, synchronized是必要的,以確保只有1在一個時間的線程可以看到,如果它們能夠加入一個表然后加入。

另外, synchronized塊還保護表列表本身,而表列表本身可能不是synchronized集合。 如果沒有synchronized塊,則這兩個線程可以同時寫入List並破壞List

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM