Я хотел бы реализовать простое кэширование тяжелых объектов в веб-JAVA-приложении. Но я не могу выяснить, как сделать это правильно.
Я пропускаю что-то, или методы ConcurrentHashMap (putIfAbsent...) недостаточно, и дополнительная синхронизация необходима?
Существует ли лучший простой API (В устройстве хранения данных памяти, никакой внешней конфигурации), чтобы сделать это?
P.
Для коллекций примитивов следует использовать запрос 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;
}
Несколько потоков могут "забегать", чтобы создать и добавить элемент для ключа, но только один должен "выиграть".
Если единственное, что вы хотите сделать, это поместить изображение на виджет без сложности графического 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;
В принципе, вы могли бы написать что-то подобное:
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)
столь же лаконичен и более идиоматичен? Вероятно, нет.
У меня была та же проблема вчера, и я решил ее, обновив каналы
pear clear-cache
pear update-channels
, прежде чем попытаться установить phpUnit.
Надеюсь, это поможет.
-121--833815-ConcurrentHashMap должна быть достаточной для ваших потребностей putIfОтсутствующий безопасен для потоков.
Не уверен, насколько проще можно получить
ConcurrentMap myCache = new ConcurrentHashMap();
Пола
В соответствии с ответом Кена, если создание тяжеловесного объекта, который позже будет выброшен, НЕ приемлемо (вы хотите гарантировать, что для каждого ключа по какой-то причине будет создан только один объект), то вы можете сделать это по...., на самом деле, не надо. Не делайте этого сами. Используйте 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 для более подробной информации)
.