Как я могу выполнить потокобезопасный моментальный снимок карты значения ключа в Java? - PullRequest
4 голосов
/ 20 марта 2009

В моем приложении есть карта ключ-значение, которая служит центральным хранилищем для хранения данных, которые используются для возврата к определенному состоянию после сбоя или перезапуска (контрольная точка).

Приложение является многопоточным, и несколько потоков могут помещать пары ключ-значение в эту карту. Один поток отвечает за регулярное создание контрольной точки, т.е. е. сериализовать карту в постоянное хранилище.

Пока пишется контрольная точка, карта должна остаться без изменений. Довольно просто избежать добавления новых элементов, но как насчет других потоков, изменяющих элементы «своих» объектов внутри карты?

Я мог бы иметь один объект, монитор которого захвачен при запуске контрольной точки, и обернуть все права на запись для любого элемента карты и его элементов в блоках, синхронизирующихся с этим объектом. Это кажется мне очень подверженным ошибкам и утомительным.

Я также могу сделать карту закрытой для контрольной точки и поместить в нее только копии переданных объектов. Но тогда я должен был бы убедиться, что копии являются глубокими копиями, и я не смог бы автоматически обновлять данные на карте, при каждом изменении отправленных объектов отправители должны были бы повторно отправлять их. Это похоже на большие накладные расходы и также подвержено ошибкам, так как я должен помнить, что код повторной отправки должен быть в нужных местах.

Какой элегантный и надежный способ решить эту проблему?

Ответы [ 2 ]

2 голосов
/ 20 марта 2009

как насчет других потоков, изменяющих элементы "своих" объектов внутри карты

Здесь у вас есть проблема :), и она не может быть решена никакими картами ...

Одним из решений будет разрешить использование на карте только неизменных объектов, но это может оказаться невозможным для вас.

В противном случае вам придется делить блокировку, чтобы все потоки могли изменять данные, на которые ссылается ваша карта, и блокировать их все во время вашего снимка; но это остановка мирного подхода ...

1 голос
/ 20 марта 2009

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

Во-первых, используйте ReadWriteLock (для чего требуется 1.5 или более поздняя версия). Поскольку ваша контрольная точка может получить блокировку чтения, она может быть уверена, что все в порядке, но когда никто не читает, производительность чтения должна быть довольно хорошей. Это все еще довольно грубая блокировка, так что вы также можете сделать # 2 ...

Во-вторых, разбить вещи. У каждой области программы может быть своя собственная карта (карта для графического интерфейса, карта для пользовательских настроек, карта для аппаратных настроек и т. Д.). У каждого будет замок, и все пойдет как обычно. Когда приходит время для контрольной точки, контрольная точка захватывает ВСЕ блокировки (чтобы все было согласованно), а затем выполняет свою работу. Подвох здесь в том, что вы определили порядок захвата замков (скажем, в алфавитном порядке), иначе вы получите тупики.

Если карты ортогональны друг другу (обновления одной не требуют обновлений для другой, чтобы быть непротиворечивыми), то самым простым может быть отправка обновлений на центральную «резервную» карту в контрольной точке, мало чем отличающуюся от чего-либо Вы описали.

Мой самый большой вопрос к вам: насколько это проблема (с точки зрения производительности)? Являются ли обновления очень частыми или редкими? Это помогло бы что-то посоветовать, поскольку моя последняя идея (предыдущий абзац) может быть медленной, но это легко и может не иметь значения.

Существует фантастическая книга под названием Параллелизм Java на практике , которая в основном представляет собой библию потоков Java. В нем обсуждается, как выяснить такие вещи и стратегии, чтобы избежать проблем или облегчить их решение. Если вы собираетесь делать больше потоков, это очень полезное чтение.

На самом деле, если ваши ключевые значения ортогональны друг другу, тогда все действительно просто. Интерфейс ConcurrentMap (существуют реализации, такие как ConcurrentHashMap ) решит ваши проблемы, поскольку они могут вносить изменения атомарно, поэтому читатели не увидят противоречивые данные. Но если у вас есть две (или более) клавиши, которые должны быть обновлены одновременно, это не покроет вас.

Надеюсь, это поможет. Потоковый доступ к разделяемым структурам данных - сложная задача.

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