TL: DR: Вызов Collection#add(E)
может вызвать исключение после получения разрешения.
Разрешения Semaphore
в этом случае представляют емкость. Когда элемент добавляется, разрешение получается , а затем происходит попытка добавить элемент во внутренний Set
. Результат вызова add
затем проверяется, чтобы убедиться, что элемент действительно был добавлен. Если элемент не был добавлен, то ранее полученное разрешение должно быть освобождено. Пока все хорошо.
Проблема в том, что Collection#add(E)
может выдать исключение. Полученное разрешение все еще должно быть выпущено в этом случае. Блок try-finally гарантирует, что если элемент не был добавлен, либо потому, что дубликаты не разрешены, либо из-за того, что было сгенерировано исключение, ранее полученное разрешение освобождается.
public boolean add(T o) throws InterruptedException {
sem.acquire(); // permit acquired before attempting to add element
boolean wasAdded = false;
try {
wasAdded = set.add(o);
return wasAdded;
} finally {
if (!wasAdded)
sem.release(); // invoked if "set.add(o)" returns false **or** throws exception
}
}
Поскольку ваша версия не имеет Блок try-finally не работает с кодом:
public boolean add(T o) throws InterruptedException {
sem.acquire(); // permit acquired before attempting to add element
boolean wasAdded = set.add(o); // if exception is thrown permit is never released
if (!wasAdded)
sem.release(); // only invoked if "set.add(o)" returns false
return wasAdded;
}
Удаление элемента не приводит к той же проблеме. Разрешение не было выдано до попытки удаления элемента, поэтому разрешение не нужно повторно получать, если элемент фактически не был удален. Это все еще так, даже если Collection#remove(Object)
выдает исключение.
public boolean remove(Object o) {
boolean wasRemoved = set.remove(o);
if (wasRemoved)
sem.release(); // won't be invoked if "set.remove(o)" returns false or throws exception
return wasRemoved;
}