Реализация кэша с помощью java ConcurrentHashMap

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

Я пропускаю что-то, или методы ConcurrentHashMap (putIfAbsent...) недостаточно, и дополнительная синхронизация необходима?

Существует ли лучший простой API (В устройстве хранения данных памяти, никакой внешней конфигурации), чтобы сделать это?

P.

15
задан Paolo1976 15 January 2010 в 08:59
поделиться

4 ответа

Для коллекций примитивов следует использовать запрос HQL следующим образом:

from Item item join item.labels lbls where 'hello' in (lbls)

PS: "" join "" требуется, поскольку "" labels "" является вариантом OneToMany или ManyToMany, скобки требуются, поскольку "" lbls "" является коллекцией

-121--1599530-

Как насчет чего-то подобного, что является O (n ^ 2)

for(each ele in the sorted array)
{
    ele = arr[i] - YOUR_NUMBER;
    let front be the pointer to the front of the array;
    let rear be the pointer to the rear element of the array.;

    // till front is not greater than rear.                    
    while(front <= rear)
    {
        if(*front + *rear == ele)
        {
            print "Found triplet "<<*front<<","<<*rear<<","<<ele<<endl;
            break;
        }
        else
        {
            // sum is > ele, so we need to decrease the sum by decrementing rear pointer.
            if((*front + *rear) > ele)
                decrement rear pointer.
            // sum is < ele, so we need to increase the sum by incrementing the front pointer.
            else
                increment front pointer.
        }
    }

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

-121--674068-

Если безопасно временно иметь более одного экземпляра для вещи, которую вы пытаетесь кэшировать, вы можете сделать кэш без блокировки, как это:

public Heavy instance(Object key) {
  Heavy info = infoMap.get(key);
  if ( info == null ) {
    // It's OK to construct a Heavy that ends up not being used
    info = new Heavy(key);
    Heavy putByOtherThreadJustNow = infoMap.putIfAbsent(key, info);
    if ( putByOtherThreadJustNow != null ) {
      // Some other thread "won"
      info = putByOtherThreadJustNow;
    }
    else {
      // This thread was the winner
    }
  }
  return info;
}

Несколько потоков могут "забегать", чтобы создать и добавить элемент для ключа, но только один должен "выиграть".

14
ответ дан 1 December 2019 в 00:54
поделиться

Если единственное, что вы хотите сделать, это поместить изображение на виджет без сложности графического API, вы также можете просто создать новый QWidget и установить фон с помощью StyleSheets. Что-то вроде:

MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
{
    ...
    QWidget *pic = new QWidget(this);
    pic->setStyleSheet("background-image: url(test.png)");
    pic->setGeometry(QRect(50,50,128,128));
    ...
}
-121--1039883-

Убедитесь, что клонированное поведение по умолчанию работает для вас. клонированная запись может оказаться недействительной в соответствии с правилами проверки.

Попробуйте использовать @ item.save! вместо @ item.save и проверьте, не возникло ли исключение. Вы также можете попробовать код непосредственно в экземпляре консоли.

In Console I figured out that clone generates the copy without ID.

Это правда. # clone фактически создает клон, но не сохраняет запись. Поэтому в действии необходимо вызвать метод сохранения, который на самом деле используется в

if @item.save # <-- here you save the record
  flash[:notice] = 'Item was successfully cloned.'
else
  flash[:notice] = 'ERROR: Item can\'t be cloned.'
end
-121--4817893-

Вместо того, чтобы помещать «тяжелые объекты» в кэш, можно использовать легкие заводские объекты для создания активного кэша.

public abstract class LazyFactory implements Serializable {

  private Object _heavyObject;

  public getObject() {
    if (_heavyObject != null) return _heavyObject;
    synchronized {
      if (_heavyObject == null) _heavyObject = create();
    }
    return _heavyObject;
  }

  protected synchronized abstract Object create();
}

// here's some sample code

// create the factory, ignore negligible overhead for object creation
LazyFactory factory = new LazyFactory() {
  protected Object create() {
    // do heavy init here
    return new DbConnection();
  };
};
LazyFactory prev = map.pufIfAbsent("db", factory);
// use previous factory if available
return prev != null ? prev.getObject() : factory.getObject;
2
ответ дан 1 December 2019 в 00:54
поделиться

В принципе, вы могли бы написать что-то подобное:

class Base
{
    public static T Get<T>(int id)
        where T : Base, new()
    {
        return new T() { ID = id };
    }

    public int ID { get; set; }
}

Тогда вы могли бы написать var p = Base.Get < Щенок > (10) . Или, если вы чувствовали себя мазохистом, вы могли бы написать Puppy.Get < Щенок > (10) или даже Kitty.Get < Щенок > ;) Во всех случаях необходимо передать тип явно, а не неявно.

В качестве альтернативы, это также работает:

class Base<T> where T : Base<T>, new()
{
    public static T Get(int id)
    {
        return new T() { ID = id };
    }

    public int ID { get; set; }
}

class Puppy : Base<Puppy>
{
}

class Kitten : Base<Kitten>
{
}

Вам все еще нужно передать тип обратно в базовый класс, который позволяет написать Puppy.Get (10) , как ожидалось.

Но все же есть ли причина писать это так, когда var p = новый Щенок (10) столь же лаконичен и более идиоматичен? Вероятно, нет.

-121--4378966-

У меня была та же проблема вчера, и я решил ее, обновив каналы

pear clear-cache
pear update-channels

, прежде чем попытаться установить phpUnit.

Надеюсь, это поможет.

-121--833815-

ConcurrentHashMap должна быть достаточной для ваших потребностей putIfОтсутствующий безопасен для потоков.

Не уверен, насколько проще можно получить

ConcurrentMap myCache = new ConcurrentHashMap();

Пола

0
ответ дан 1 December 2019 в 00:54
поделиться

В соответствии с ответом Кена, если создание тяжеловесного объекта, который позже будет выброшен, НЕ приемлемо (вы хотите гарантировать, что для каждого ключа по какой-то причине будет создан только один объект), то вы можете сделать это по...., на самом деле, не надо. Не делайте этого сами. Используйте google-коллекции (теперь guava) MapMaker class:

Map<KeyType, HeavyData> cache = new MapMaker<KeyType, HeavyData>()
  .makeComputingMap(new Function<KeyType, HeavyData>() {
      public HeavyData apply(KeyType key) {
          return new HeavyData(key); // Guaranteed to be called ONCE for each key
      }
  });

Тогда простой cache.get(key) просто работает и полностью избавляет вас от необходимости беспокоиться о каверзных аспектах параллельности и синхронизации.

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

Map<....> cache = new MapMaker<....>()
  .expiration(30, TimeUnit.MINUTES)
  .makeComputingMap(.....)

и вы также можете легко использовать мягкие или слабые значения для ключей или данных, если это необходимо (смотрите Javadoc для более подробной информации)

.
25
ответ дан 1 December 2019 в 00:54
поделиться
Другие вопросы по тегам:

Похожие вопросы: