Как называется этот "Шаблон дизайна контейнера"?

При создании моего приложения. Архитектура Я столкнулся с необходимостью в одну структуру, которая будет описана ниже.

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

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

Идея близка к шаблону читатель-писатель. У нас есть "контейнер", в который мы можем добавлять объекты по ключу (). А также мы можем получить эти объекты по ключам, удалив их из контейнера.

Итак, реализованный класс должен иметь два метода:

void putObject(Key key, Object object);
Object getObject(Key key); // remove <Key,Object> from container.

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

  1. Если нет никакого объекта, связанного с ключом, то при вызове метода get(Key key) поток вызывающей стороны должен ЖДАТЬ объекта в этом контейнере.
  2. Когда другой поток вызовет метод 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));
    }
}

Глядя на ваш дизайн, мне, что вы описываете

У нас есть "контейнер", в который мы можем добавлять объекты по ключу (). А также мы можем получить эти объекты по ключам, удалив их из контейнера. Этот контейнер должен работать в многопоточной среде

близко к параллельному объектному пулу. Он использует набор инициализированных объектов, готовых к использованию. Клиент пула будет запрашивать объект из пула и выполнять операции с возвращенным объектом.

Единственное реальное отличие, которое я вижу, это то, что вы получаете объекты на основе ваших собственных критериев.

Другие вопросы по тегам