finally子句中的信号量处理

问题描述 投票:1回答:1

我正在阅读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;
}

最终尝试放置而不是简单的语句有什么好处?

java concurrency semaphore
1个回答
0
投票

在这种情况下,Semaphore的许可表示容量。添加元素后,会获得许可,然后尝试将元素添加到内部Set。然后检查调用add的结果,以确保实际添加了元素。如果未添加元素,则必须释放先前获得的许可。到目前为止一切都很好。问题是Collection#add(E)可能引发异常。在这种情况下,必须仍然释放获得的许可证。 try-finally块可确保如果不添加元素(由于不允许重复或由于引发异常)而释放了先前获得的许可。

Collection#add(E)

删除元素没有相同的问题。在尝试删除该元素之前,没有释放任何许可,因此,如果实际上并未删除该元素,则无需重新获取许可。即使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
  }
}
引发异常,情况仍然如此。

Collection#remove(Object)

© www.soinside.com 2019 - 2024. All rights reserved.