【问题标题】:Proper way to try-catch a semaphore尝试捕获信号量的正确方法
【发布时间】:2013-02-28 15:23:07
【问题描述】:

在 try-catch 块中包装信号量操作的正确方法是什么?如果获取操作在获取了一些(但不是全部)请求的许可后被中断,会发生什么情况?你怎么知道又要释放多少?释放是否应该进入“最终”块,但是如果操作被中断,您是否可能释放您没有获得的许可?

try {
    lock.acquire(permits);

    //Do some things that require synchronization

    //Make sure to release all of the permits again!
    lock.release(permits);
} catch (InterruptedException e) {
    log.error("Interrupted!");
}

【问题讨论】:

  • “如果获取操作在获取了一些(但不是全部)请求的许可后被中断,会发生什么?” -- 不要造成僵局!

标签: java try-catch semaphore


【解决方案1】:

Semaphore.acquire(int) 方法是全有或全无操作,要么获得所有请求的许可,要么阻止。您可以在您的代码周围使用双重尝试,或者让(可能的)中断异常从获取调用堆栈中冒泡。

双重尝试块:

try {
    lock.acquire(permits);

    try {
        // do some stuff here
    } finally {
        lock.release(permits);
    }
} catch(final InterruptedException ie) {
    // handle acquire failure here
}

气泡“采集”异常:

lock.acquire(permits);

try {
    // do some stuff here
} finally {
    lock.release(permits);
}

切线,请记住信号量必须通过严格的编程约定保持平衡,因此您应该始终释放尽可能多的许可。

【讨论】:

  • 好吧,只是为了确保我很清楚,在获取所有请求的许可之前,获取方法实际上并没有获取任何许可?既然如此,InterruptedException 是否意味着没有获得许可,也不需要释放?
  • @tdimmig - 是的,你明白了。
【解决方案2】:

BoundedHashSet中的add方法为例,

    public boolean add(T o) throws InterruptedException {
        sem.acquire();
        boolean wasAdded = false;
        try {
            wasAdded = set.add(o);
            return wasAdded;
        } finally {
            if (!wasAdded)
                sem.release();
        }
    }

如果sem.acquire(); 抛出InterruptedException,则跳过try 块和finally 块。

否则,我们成功获取信号量,try块和finally块将被一并执行。也就是说,我们将释放与我们获得的相同数量的许可证。

【讨论】:

    【解决方案3】:

    要添加@Perception 的答案,您可以选择分离嵌套的双try-catch 并在acquire 块上添加重试,这适合我的用例。

    int retry_limit = 10;
    boolean acquired = lock.tryAcquire(permits);
    for (int i=0; i < retry_limit && !acquired; ++i) {
        try {
            Thread.sleep(1000);
        }
        acquired = lock.tryAcquire(permits);
    }
    if (!acquired) {
        throw new IllegalStateException("Unable to acquire permits");
    }
    try {
        // do some stuff here
    } catch(InterruptedException ie) {
        // handle acquire failure here
    } catch(Exception ex) {
        // handle other exceptions here
    } finally {
        lock.release(permits);
    }
    

    【讨论】:

      猜你喜欢
      • 2011-04-18
      • 2015-07-21
      • 1970-01-01
      • 2013-01-09
      • 2018-05-16
      • 2021-02-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多