ReentrantReadWriteLock - много читателей одновременно, по одному писателю за раз? - PullRequest
10 голосов
/ 12 мая 2011

Я несколько новичок в многопоточных средах и пытаюсь найти лучшее решение для следующей ситуации:

Я читаю данные из базы данных один раз в день утром и сохраняю ихв HashMap в объекте Singleton.У меня есть метод установки, который вызывается только тогда, когда происходит изменение БД в течение дня (что будет происходить 0-2 раза в день).

У меня также есть геттер, который возвращает элемент на карте, и этот метод вызывается сотни раз в день.

Меня беспокоит случай, когда геттер вызывается, пока яЯ очищаю и воссоздаю HashMap, таким образом, пытаясь найти элемент в пустом / неправильно сформированном списке.Если я синхронизирую эти методы, это предотвращает одновременный доступ к геттеру двух читателей, что может стать узким местом в производительности.Я не хочу слишком сильно снижать производительность, поскольку записи случаются так редко.Если я использую ReentrantReadWriteLock, будет ли это вызывать очередь для любого, кто вызывает геттер, до снятия блокировки записи?Позволяет ли несколько читателей одновременно получать доступ к геттеру?Будет ли принудительно применяться только один писатель за раз?

Кодирование - это всего лишь вопрос ...

private final ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();
private final Lock read = readWriteLock.readLock();
private final Lock write = readWriteLock.writeLock();

public HashMap getter(String a) {
    read.lock();
    try {
        return myStuff_.get(a);            
    } finally {
        read.unlock();
    }
}

public void setter() 
{
    write.lock();
    try {
        myStuff_ = // my logic
     } finally {
          write.unlock();
    }
}

Ответы [ 3 ]

14 голосов
/ 13 мая 2011

Другим способом достижения этого (без использования блокировок) является шаблон копирования при записи. Это хорошо работает, когда ты не пишешь часто. Идея состоит в том, чтобы скопировать и заменить само поле. Это может выглядеть следующим образом:

private volatile Map<String,HashMap> myStuff_ = new HashMap<String,HashMap>();

public HashMap getter(String a) {
    return myStuff_.get(a);
}

public synchronized void setter() {
    // create a copy from the original
    Map<String,HashMap> copy = new HashMap<String,HashMap>(myStuff_);
    // populate the copy
    // replace copy with the original
    myStuff_ = copy;
}

При этом читатели полностью параллельны, и единственным штрафом, который они платят, является изменчивое чтение на myStuff_ (которое очень мало). Авторы синхронизируются для обеспечения взаимного исключения.

2 голосов
/ 12 мая 2011

Да, если блокировка записи удерживается потоком, тогда другие потоки, обращающиеся к методу getter, блокируют, так как они не могут получить блокировку чтения. Так что ты в порядке здесь. Для получения более подробной информации, пожалуйста, прочитайте JavaDoc ReentrantReadWriteLock - http://download.oracle.com/javase/6/docs/api/java/util/concurrent/locks/ReentrantReadWriteLock.html

0 голосов
/ 12 мая 2011

Вы запускаете эту вещь в начале дня ... вы будете обновлять ее 0-2 раза в день, и вы читаете ее 100 раз в день.Предполагая, что чтение займет, скажем, 1 полную секунду (длительное время) в течение 8 часов в день (28 800 секунд), у вас все еще очень низкая нагрузка чтения.Глядя на документы по ReentrantReadWriteLock, вы можете «настроить» режим так, чтобы он был «честным», что означает, что поток, который ждал дольше всего, получит блокировку.Поэтому, если вы установите справедливость, я не думаю, что ваши потоки записи будут голодать.

Ссылки

ReentrantReadWriteLock

...