Перезагрузка кеша - PullRequest
       11

Перезагрузка кеша

1 голос
/ 02 ноября 2009

Мне нужно хранить карту поиска в памяти на сервлете. Карта должна быть загружена из файла, и всякий раз, когда файл обновляется (что не очень часто), карта должна перезагружаться в том же потоке, который выполняет поиск.

Но я не уверен, как реализовать эту функциональность потокобезопасным способом. Я хочу убедиться, что перезагрузка происходит не более одного раза.

public class LookupTable
{

    private File file;
    private long mapLastUpdate;
    private Map<String, String> map;

    public String getValue(String key)
    {
        long fileLastUpdate = file.lastModified();
        if (fileLastUpdate > mapLastUpdate)
        {
         // Only the first thread should run the code in the synchronized block.
         // The other threads will wait until it is finished. Then skip it.

            synchronized (this)
            {
                Map newMap = loadMap();
                this.map = newMap;
                this.mapLastUpdate = fileLastUpdate;
            }
        }

        return map.get(key);
    }

    private Map<String, String> loadMap()
    {
        // Load map from file.
        return null;
    }
}

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

Спасибо

Ответы [ 4 ]

3 голосов
/ 06 июня 2014

Я бы предложил вам использовать imcache . Создайте параллельный кеш с загрузчиком кеша следующим образом:

Cache<String,LookupTable> lookupTableCache = CacheBuilder.
   concurrentHeapCache().cacheLoader(new CacheLoader<String, LookupTable>() {
   public LookupTable load(String key) {
   //code to load item from file.
   }
}).build();
2 голосов
/ 02 ноября 2009

Как рекомендует z5h, вам нужно защитить свое состояние (fileLastUpdate> mapsLastUpdate) той же блокировкой, которая используется для сохранения атомарной перезагрузки файла.

Я думаю об этом так: посмотреть на все переменные-члены в классе и выяснить, какие гарантии безопасности потоков им нужны. В вашем случае, ни один из членов (File, long, HashMap - хорошо, я предполагаю, что HashMap) не является потокобезопасным, и, следовательно, все они должны быть защищены блокировкой. Они также все участвуют в инварианте (все они изменяются вместе) вместе, поэтому они должны быть защищены той же блокировкой.

Ваш код, обновленный и использующий аннотации (это просто информация, они ничего не приводят в исполнение!), Предложенный Java Concurrency In Practice (отличная книга для всех Java разработчики должны читать:))

/**
* Lookup table that automatically reloads itself from a file
* when the filechanges.
*/
@ThreadSafe
public class LookupTable
{
    @GuardedBy("this")
    private long mapLastUpdate;
    @GuardedBy("this")
    private final File file;
    @GuardedBy("this")
    private Map<String, String> map;

    public LookupTable(File file)
    {
        this.file = file;
        this.map = loadMap()
    }

    public synchronized String getValue(String key)
    {
        long fileLastUpdate = file.lastModified();
        if (fileLastUpdate > this.mapLastUpdate)
        {
            // Only the first thread should run the code in the synchronized block.
            // The other threads will wait until it is finished. Then skip it.
            Map newMap = loadMap();
            this.map = newMap;
            this.mapLastUpdate = fileLastUpdate;
        }
        return map.get(key);
    }

    private synchronized Map<String, String> loadMap()
    {
        // Load map from file.
        return null;
    }
}

Это будет безопасно, но оно полностью синхронизировано: только один поток выполняет поиск на карте одновременно. Если вам нужен параллелизм при поиске, вам понадобится более сложная схема. Реализация будет зависеть, среди прочего, от того, позволят ли потоки видеть старую версию справочной таблицы во время загрузки новой.

Если вы сделали окончательный элемент карты и защитили его ReadWriteLock , вы можете получить некоторый удар. Трудно предсказать, сколько у вас может быть разногласий по этой блокировке, из ограниченной информации здесь.

0 голосов
/ 02 ноября 2009

Ваша проверка должна быть в синхронизированном блоке. В противном случае несколько потоков могут прочитать (fileLastUpdate> mapLastUpdate) как true, а затем все блокировать код обновления. Худший из обоих миров.

0 голосов
/ 02 ноября 2009

Если файл на самом деле имеет формат файла свойств (# строк в виде комментариев и ключ = строк в качестве пар ключ / значение), рассмотрите возможность использования java.util.ResourceBundle . Его реализация по умолчанию ResourceBundle.Control автоматически перезагрузит файл через определенные промежутки времени. Вы даже можете переопределить его с помощью пользовательской реализации.

Удачи.

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