потокобезопасность карты при использовании UUID в качестве ключа - PullRequest
0 голосов
/ 26 октября 2019

Существует служба, которая содержит поле final.

@Service
public class RegularService {
    private final DataMap map = new DataMap();
    ....
}

Это поле final имеет класс DataMap, который выглядит примерно так

class DataMap {
    private Map<UUID, String> content1 = new HashMap<>();
    private Map<UUID, String> content2 = new HashMap<>();

    void updateContent(UUID id, String data) {
        if (content1.containsKey(id)) {
           ....
           return;
        }


        if (content2.containsKey(id)) {
            content1.put(id, data);
            content2.remove(id);
            return;
        }
        content2.put(id, data);
    }

Вопросесть ли в updateContent состояние гонки? Дело в том, что использование UUID в теории означает, что разные потоки никогда не смогут получить доступ к одним и тем же записям ...

Если это так, то необходимо ли синхронизировать весь метод updateContent или просто использоватьConcurrentHashMap хватит?

Ответы [ 2 ]

1 голос
/ 28 октября 2019

потокобезопасность карты при использовании UUID в качестве ключа

Потоковая безопасность карт на самом деле не имеет никакого отношения к рассматриваемому ключевому объекту. То, что UUID.randomUUID() возвращает уникальный UUID, не гарантирует безопасность потока. Проблема заключается в синхронизации памяти и том, как потоки будут видеть и публиковать изменения на картах и ​​координировать множественные операции с картами.

Вопрос в том, имеет ли updateContent() состояние гонки?

Да, это так. Прежде всего, вы не можете обновить Map, используя несколько потоков, без использования синхронизированной или одновременной реализации Map. ConcurrentHashMap позаботится об изменениях карт и публикации памяти между потоками, чтобы синхронизировать их. Но поскольку вы выполняете несколько операций с картами, которые должны быть скоординированы, вам необходимо добавить дополнительную синхронизацию.

Если это так, то необходимо синхронизировать весь метод updateContent() илиДостаточно ли просто использовать ConcurrentHashMap?

Поскольку вы вносите несколько изменений в 2 карты, вам нужно будет использовать synchronized или иным образом заблокировать несколько операций. Как только вы это сделаете, вам не нужно будет использовать ConcurrentHashMap. Вы можете либо сделать метод synchronized, заблокировать одну из карт, либо сделать конкретный final Object lockObject = new Object(), чтобы использовать его для блокировки операций.

Например, без блокировки нет ничего, что защищаетThread1, чтобы увидеть, что content1 не содержит идентификатор XXX, а затем перейдите к проверке content2 прямо перед тем, как thread2 добавит его к content1. Так что thread1 перезапишет data в thread2, а это не то, что вы хотели бы предположить.

1 голос
/ 26 октября 2019

Дело в том, что теоретически использование UUID означает, что одни и те же записи никогда не будут доступны для разных потоков ...

Это просто не соответствует действительности. Это не гарантировано. Как вы пришли к такому выводу? Мне интересно знать.

Если это так, тогда нужно ли синхронизировать весь метод updateContent или достаточно будет использовать только ConcurrentHashMap?

Вам не обязательнодолжны синхронизировать всю функцию, только бит, который изменяет карту. Вы можете использовать ConcurrentHashMap для решения этой проблемы, но есть серьезные потери производительности.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...