Как называется этот "Шаблон дизайна контейнера"?
При создании моего приложения. Архитектура Я столкнулся с необходимостью в одну структуру, которая будет описана ниже.
Я почти уверен, что существует хорошо известный шаблон проектирования с той же функциональностью, потому что я думаю, что проблема, для которой я разрабатываю его, действительно распространена.
Я пишу свою собственную реализацию этого, но я всегда стараюсь использовать реализации шаблонов на "встроенном языке", поэтому, пожалуйста, помогите мне назвать эту конструкцию.
Идея близка к шаблону читатель-писатель. У нас есть "контейнер", в который мы можем добавлять объекты по ключу (). А также мы можем получить эти объекты по ключам, удалив их из контейнера.
Итак, реализованный класс должен иметь два метода:
void putObject(Key key, Object object);
Object getObject(Key key); // remove <Key,Object> from container.
Следующее самое интересное. Этот контейнер должен работать в многопоточной среде следующим образом:
- Если нет никакого объекта, связанного с ключом, то при вызове метода get(Key key) поток вызывающей стороны должен ЖДАТЬ объекта в этом контейнере.
- Когда другой поток вызовет метод putObject(ключ-ключ, объект-объект), он должен проверить, существует ли какой-либо поток, ожидающий именно этого объекта, и, если это так, - подать сигнал и активировать ожидающий поток.
Я думаю, что это общая структура, есть ли у нее "официальное" название?
Моя реализация Java этого шаблона:
private static interface BlackBox {
public void addObject(IdObject object);
public IdObject getObject(ObjectId id);
}
private static class BlackBoxImpl implements BlackBox {
private final Lock conditionLock = new ReentrantLock();
private final Map<ObjectId, IdObject> savedObjects;
private final Map<ObjectId, Condition> waitingConditions;
public BlackBoxImpl() {
this.savedObjects = new ConcurrentHashMap<ObjectId, IdObject>(20);
this.waitingConditions = new ConcurrentHashMap<ObjectId, Condition>(20);
}
@Override
public void addObject(IdObject object) {
savedObjects.put(object.getId(), object);
if (waitingConditions.containsKey(object.getId())) {
Condition waitCondition = waitingConditions.get(object.getId());
conditionLock.lock();
waitCondition.signal();
conditionLock.unlock();
}
}
@Override
public IdObject getObject(ObjectId id) {
if (savedObjects.containsKey(id)) {
return savedObjects.get(id);
} else {
conditionLock.lock();
Condition waitCondition = conditionLock.newCondition();
waitingConditions.put(id, waitCondition);
waitCondition.awaitUninterruptibly();
conditionLock.unlock();
return savedObjects.get(id);
}
}
}
private static interface IdObject {
public ObjectId getId();
}
private static class IdObjectImpl implements IdObject {
protected final ObjectId id;
public IdObjectImpl(ObjectId id) {
this.id = id;
}
@Override
public ObjectId getId() {
return id;
}
}
private static interface ObjectId {
}
private static class ObjectIdImpl implements ObjectId {
}
2 ответа
Я бы, наверное, использовал что-то вроде
ConcurrentMap<K,BlockingQue<V>>.
Используйте параллельные методы карты, чтобы добавить пару. Возьми из своей очереди значение. Используйте ArrayBlockingQue(1).
Возможно, что-то вроде этого:
static class MultiQueue<K, V> {
// The base structure.
final ConcurrentMap<K, BlockingQueue<V>> queues = new ConcurrentHashMap<>();
/**
* Put an item in the structure.
*
* The entry in the map will be created if no entry is currently there.
*
* The value will then be posted to the queue.
*/
public void put(K k, V v) throws InterruptedException {
// Make it if not present.
ensurePresence(k).put(v);
}
/**
* Get an item from the structure.
*
* The entry in the map will be created if no entry is currently there.
*
* The value will then be taken from the queue.
*/
public void get(K k) throws InterruptedException {
// Make it if not present - and wait for it.
ensurePresence(k).take();
}
private BlockingQueue<V> ensurePresence(K k) {
// Make it if not present.
return queues.computeIfAbsent(k, v -> new ArrayBlockingQueue(1));
}
}
Глядя на ваш дизайн, мне, что вы описываете
У нас есть "контейнер", в который мы можем добавлять объекты по ключу (). А также мы можем получить эти объекты по ключам, удалив их из контейнера. Этот контейнер должен работать в многопоточной среде
близко к параллельному объектному пулу. Он использует набор инициализированных объектов, готовых к использованию. Клиент пула будет запрашивать объект из пула и выполнять операции с возвращенным объектом.
Единственное реальное отличие, которое я вижу, это то, что вы получаете объекты на основе ваших собственных критериев.