Одна Блокировка может быть связана со многими Условиями. Блокировка — это «объект», каждое условие — это «ожидающий набор». Это позволяет использовать независимые условия для совместного использования критической секции. Например, рассмотрим ограниченную задачу производителей-потребителей. Один из способов решить эту проблему — иметь одну блокировку, защищающую очередь, и два независимых набора ожидания: один для производителей, ожидающих, когда слот поместит элемент в очередь, другой — для потребителей, ожидающих получения предметов. Используя старые добрые synchronized
и wait/notify
API, лучше всего мы можем сделать следующее:
Недостатком этого является пробуждение как производителей, так и потребителей при каждом изменении в очереди, даже если это не может позволить данному потоку продолжаться (например, потребитель пробуждается, когда какой-то другой потребитель берет элемент из очереди). . Используя Lock/Condition API, мы можем реализовать решение, которое разделяет ожидающих потребителей и производителей и, следовательно, уменьшает избыточные пробуждения и проверки:
Lock lock = new ReentrantLock();
Condition hasPlace = lock.newCondition();
Condition hasItems = lock.newCondition();
режиссер:
lock.lock();
try {
while (queue.isFull()) {
hasPlace.await();
}
queue.put(sth);
hasItems.signal();
} finally {
lock.unlock();
}
потребитель:
lock.lock();
try {
while (queue.isEmpty()) {
hasItems.await();
}
product = queue.take();
hasPlace.signal();
} finally {
lock.unlock();
}
Таким образом, потребитель ждет, пока производители произведут какой-либо предмет (условие hasItems), и, удаляя предмет из очереди, уведомляет производителей о наличии свободного места (условие hasPlace). Оба условия связаны с одной и той же критической секцией (Lock), поэтому мы сохраняем обычные гарантии исключения и снятия блокировки во время ожидания, получая при этом возможность разделять очереди ожидания.
person
Marcin Łoś
schedule
28.08.2013