2017-02-01 2 views
0

Существует интенсивный пример использования чтения, в котором несколько потоков считываются из HashMap, и каждые 30 минут позволяют утверждать, что он истекает и обновляет всю карту. Максимальный размер карты будет находиться в диапазоне от 2 МБ до 200 МБ.HashMap с несколькими чтениями и периодическими записями

Итак, в настоящее время решение, которое, как я думаю, состоит в том, чтобы иметь HashMap с несколькими считывателями, и как только он истечет, поток демона будет извлекать данные из источника данных и создавать новую карту, и после ее завершения блокируется старый HashMap, а затем скопируйте вновь созданную карту на старую. Правильный ли подход, и если да, там лучший подход, а если нет, то какой правильный подход. Будет ли копирование данных на новую карту займет больше времени?

Целью является максимальное количество запросов на чтение.

+1

См. Http://stackoverflow.com/questions/104184/is-it-safe-to-get-values-from-a-java-util-hashmap-from-multiple-threads-no-modi. – gsl

ответ

0

Во-первых, обратите внимание на связанный вопрос (из комментариев выше) и его ответы. Повторные здесь: Is it safe to get values from a java.util.HashMap from multiple threads (no modification)?

Поскольку вы уже строите новую (и, видимо, полную) карту, чтобы заменить старую, не обновлять существующий HashMap на месте. Это будет медленнее, и доступ к карте будет заблокирован при его обновлении.

Просто замените старую карту на новую:

public class HashMapAccessController 
{ 
    protected HashMap map = null; 

    // version - increment this on each update 
    // (assuming generation of a new map version 
    // takes measurable time, rollover is a 
    // problem for the next civilization...) 
    protected long version = 0; 

    public HashMapAccess(HashMap newMap) 
    { 
     map = newMap; 
    } 

    public synchronized long getVersion() 
    { 
     return(version); 
    } 

    synchronized HashMap getMap() 
    { 
     return(map); 
    } 

    synchronized HashMap updateMap(HashMap newMap) 
    { 
     version++; 
     HashMap oldMap = map; 
     map = newMap; 
     return(oldMap); 
    } 
} 

Просто убедитесь, что вы ТОЛЬКО чтение из любой карты вернулся из getMap() и не пытайтесь обновить его. Опять же, см. Связанный вопрос: Is it safe to get values from a java.util.HashMap from multiple threads (no modification)?

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

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

+0

Если интенсивность чтения не была бы лучше, если бы карта деревьев была лучше? –

+0

@JonathanRosenne Вопрос задан «HashMap», поэтому ... Объект контроля доступа должен, вероятно, просто использовать «Карта». Черт, он может просто использовать «Объект». –

+0

@ AndrewHenle: Спасибо, да, этот недостаток понятен и приемлем. Еще раз спасибо. – user3331132

0

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

Звучит правильно. Если, как вы подразумеваете в своем сообщении, никто не , изменяя HashMap после того, как он был создан, вы можете безопасно использовать его с несколькими потоками, если вы делите его правильно. Чтобы обеспечить неизменность, вы должны обернуть карту, используя Collection.unmodifiableMap(map).

Чтобы поделиться картой с потоками, вам нужно будет сделать это поле volatile, доступное всем потокам. Что-то вроде:

protected volatile HashMap map = null; 

С ним быть volatile, то вам не нужно делать какие-либо блокировки.You метод обновления, то выглядит следующим образом:

// no need to have synchronized here 
HashMap updateMap(HashMap newMap) { 
    HashMap oldMap = this.map; 
    this.map = Collection.unmodifiableMap(newMap); 
    return oldMap; 
} 

Ни один из ваших методов не должны быть synchronized, а также. volatile поля будут намного лучше, потому что потоки будут пересекаться только с защитой памяти чтения, когда они получат доступ к общей карте и только барьер памяти записи при ее обновлении. С ключевым словом synchronized потоки каждый раз пересекают барьер чтения и записи. Хуже того, ключевое слово synchronized имеет блокировку накладных расходов, которая защищает мьютекс, который вам не нужен.

Будет ли копирование данных на новую карту занимать больше времени?

Копирование данных на новую карту потребует времени, но не более, чем типичное копирование данных между HashMaps. То, что равно, отличается тем, что доступ к полям volatile может быть намного медленнее, чем прямой доступ к полю из-за пересекающихся барьеров памяти.

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