2013-11-16 2 views
0

У меня есть объект Map, который соответствует пару значений ключа, хранящейся в файле.Синхронизация объекта карты

private static Map myMap; 

Существует менеджер класс для этого объекта Map, который имеет метод GetMap(), который возвращает объект к абоненту.

public static Map getMap() 

Он также имеет синхронизированный метод saveMap(), который сохранить содержимое обратно в файл

public static synchronized void saveMap(Map map) 

Проблема заключается в том, что есть темы, которые получает объект на карте, но не хотят save, т. е. они не вызывают saveMap().

Предположим, что thread1 получает объект карты и вносит в него изменения, т. Е. Добавляет пару значений ключа к карте. key1 = value1 и после завершения задачи удаляет эту пару ключ-значение с карты. Между ними находится другой поток thread2, который добавляет еще пару ключ-значение для отображения key2 = значение2 и сохраняет его до того thread1 фактически удалить key1 с карты. Это приводит к сохранению ключа key1 = value1 и key2 = value2 в файле. Это не то, что я хочу.

Как я могу преодолеть эту ситуацию? Я думал о том, чтобы изменить метод getMap() с чем-то вроде

public Map getMap(boolean readonly) { 
     if (readonly) 
      return myMap.clone(); 
     return myMap; 
} 

Будет ли это решить мою проблему?

Примечание: я не хочу использовать мьютексы и блокировать объект Map, так как у меня есть длительные процессы, которые блокируют другие потоки.

+0

Если это не то, что вы хотите, то почему вы разрешаете этому случиться? Возможно, вы должны поставлять * копии * карты в потоки, моды которых вы не хотите сохранять. – EJP

+0

@EJP Разве это не то, что предлагает его предлагаемый код? –

+2

Независимо от того, что вы делаете, если у вас есть несколько потоков, которые вносят изменения в карту, ваш код не является потокобезопасным и, рано или поздно, карта будет находиться в противоречивом состоянии. Вы не должны открывать карту вообще. Инкапсулируйте его в свой класс и синхронизируйте ** каждый ** доступ к карте. –

ответ

3

Я бы сделал одну из двух вещей.

Первый, который я рекомендую, НЕ ПРОПУСТИТЕ КОПИИ КАРТЫ. Нет способа гарантировать, что значения не будут потеряны/перезаписаны из чередующихся, получаются/сохраняются, кроме многопоточных проблем, из-за отсутствия синхронизированного объекта.

В вашем классе менеджера удалены getMap() и saveMap() и замените их getValue() и setValue(). Я бы сделал эти методы синхронизированными или заменил карту ConcurrentMap. Таким образом, у вас нет людей, которые держатся за экземпляры всей карты.

Второй вариант заключается в замене Карты на Hashtable. который синхронизирован и потокобезопасен, но медленнее. Это избавит вас от некоторых, но не всех, ваших проблем. У вас все еще есть свободные ссылки на карту, бегущую вокруг вашего кода.

+0

Спасибо. Я поеду на вариант 1. Cheers :) –

+2

Если вы хотите синхронизированную карту, не используйте старую устаревшую Hashtable. Используйте 'Collections.synchronizedMap (anyMap)'. –

+0

@dj_segfault: Если я использую синхронизированный для каждого метода, нет ли шанса на тупик? Вам лучше какой-то объект блокировки уровня класса? Мои методы не статичны. –

Смежные вопросы