finally 子句中的信号量操作
Semaphore manipulation in finally clause
我正在阅读 Java 并发实践。
public class BoundedHashSet<T> {
private final Set<T> set;
private final Semaphore sem;
public BoundedHashSet(int bound) {
this.set = Collections.synchronizedSet(new HashSet<T>());
sem = new Semaphore(bound);
}
public boolean add(T o) throws InterruptedException {
sem.acquire();
boolean wasAdded = false;
try {
wasAdded = set.add(o);
return wasAdded;
} finally {
if (!wasAdded)
sem.release();
}
}
public boolean remove(Object o) {
boolean wasRemoved = set.remove(o);
if (wasRemoved)
sem.release();
return wasRemoved;
}
}
我不知道为什么 add
方法有 try-finally 子句而 remove
方法没有。
我觉得像下面这样简单点就可以了
public boolean add(T o) throws InterruptedException {
sem.acquire();
boolean wasAdded = set.add(o);
if (!wasAdded)
sem.release();
return wasAdded;
}
放置 try-finally 而不是简单的语句有什么好处?
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;
}
我正在阅读 Java 并发实践。
public class BoundedHashSet<T> {
private final Set<T> set;
private final Semaphore sem;
public BoundedHashSet(int bound) {
this.set = Collections.synchronizedSet(new HashSet<T>());
sem = new Semaphore(bound);
}
public boolean add(T o) throws InterruptedException {
sem.acquire();
boolean wasAdded = false;
try {
wasAdded = set.add(o);
return wasAdded;
} finally {
if (!wasAdded)
sem.release();
}
}
public boolean remove(Object o) {
boolean wasRemoved = set.remove(o);
if (wasRemoved)
sem.release();
return wasRemoved;
}
}
我不知道为什么 add
方法有 try-finally 子句而 remove
方法没有。
我觉得像下面这样简单点就可以了
public boolean add(T o) throws InterruptedException {
sem.acquire();
boolean wasAdded = set.add(o);
if (!wasAdded)
sem.release();
return wasAdded;
}
放置 try-finally 而不是简单的语句有什么好处?
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;
}