在Java中释放信号量对象的正确方法是什么?
这是大多数在线资源中编写的代码。但这是不正确的,因为考虑线程阻塞时的场景,然后中断。 即使线程尚未获得锁,它仍将释放锁。这是不正确的。那么,在java中释放信号量的正确实现是什么呢在Java中释放信号量对象的正确方法是什么?,java,multithreading,concurrency,semaphore,Java,Multithreading,Concurrency,Semaphore,这是大多数在线资源中编写的代码。但这是不正确的,因为考虑线程阻塞时的场景,然后中断。 即使线程尚未获得锁,它仍将释放锁。这是不正确的。那么,在java中释放信号量的正确实现是什么呢 Semaphore lock = new Semaphore(1); add(){ try { lock.acquire(); // critical section } catch (InterruptedException e) {
Semaphore lock = new Semaphore(1);
add(){
try {
lock.acquire();
// critical section
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}finally{
lock.release()
}
}
我认为这是正确的解决方案:-。是吗
try {
lock.acquire();
try {
// do some stuff here
} finally {
lock.release();
}
} catch(InterruptedException ie) {
Thread.currentThread().interrupt();
throw new RuntimeException(ie);
}
信号量没有所有权的概念。许可证不是真的,它只是信号灯保持的计数。所以问题是,在方法执行之后,计数是否正确? 如果你被打断了,你会留下一个或两个可用的许可证吗 api文档中Oracle站点上的信号量示例没有任何finally块,在很多情况下它们并不相关 如果您使用此信号量来实现互斥,并且它只有一个许可证,我希望它应该有一个try finally块,就像使用锁一样(来自): 如果代码接受InterruptedException并让线程继续运行,那么方法末尾的计数是否正确就变得很重要,它可能会阻止其他调用获取许可 每当我得到某样东西,使用它,然后释放它时,我使用的一般模式是将它置于try块之上,然后在try块中使用它,在finally块中关闭/释放/清理。这适用于IO、JDBC资源等。您可以尝试避免这种情况,将采集放在try块中,然后 在清理之前检查空值。您还可以尝试在finally块中执行太多操作,在close时无法捕获异常,并造成资源泄漏。最好尽量减少finally块中的代码量 一个正确的例子是(摘自Java并发性一书) 在实践中): 这显示了一个带有finally的try块,该块执行一些清理(如果结果没有向集合中添加任何内容,则释放许可证),其中在输入try块之前调用acquire 在本例中,如果acquire调用被移动到try块中,则无所谓。我认为将调用置于try块之上是更好的样式,但在本例中,它不会影响正确性,因为它使用标志来决定是否发布许可证 我将使用一个类似于jcip示例中的标志,在获取后将其设置为true,并且仅在设置了标志时才释放。这样您就可以将acquire放在try块中
boolean wasAcquired = false;
try {
sem.acquire();
wasAcquired = true;
// crit sect
} catch (InterruptedException e) {
Thread.currentThread.interrupt();
} finally {
if (wasAcquired)
sem.release();
}
或考虑获取不中断()。但是想想看,如果这些调用没有抛出InterruptedException,那么在收到中断请求时,代码的哪一部分确保代码实际停止工作?看起来您可能会陷入一个无效的循环,线程尝试获取、抛出InterruptedException、捕获它并设置中断状态,然后在下一次线程尝试获取时重复执行相同的操作。抛出InterruptedException可以让您快速响应取消请求,同时确保在finally块中完成清理
即使线程尚未获得锁,它仍将释放锁。这是不正确的 不,不是。这里没有什么不合适的。从: 不要求释放许可证的线程必须通过调用acquire()获得该许可证。
信号量的正确使用由应用程序中的编程约定确定
这里没有需要解决的问题。只需添加一个标志,指示是否已获取锁:
boolean acquired = false;
try {
lock.acquire();
acquired = true;
// critical section
} catch (InterruptedException e) {
// do anything
} finally {
if (acquired) {
lock.release()
}
}
另一种解决方案是使用
信号量。AcquireUnterruptibly()
acquire()抛出异常,因此必须进行尝试。您可以发布正确的实现吗?这并不意味着它必须在同一个try块中。而且InterruptedException可能甚至不应该被处理,但应该被处理。我想在代码本身中处理异常。@Karen:您可以使用AcquireUnterruptibly()而不必弄乱它。非常感谢您的解释。release()的调用信号量的Javadoc允许并不意味着问题中的代码是正确的。如果acquire()
被中断,它仍然会意外地增加许可证的数量,这在大多数情况下可能是一个错误。EJP:假设你是我的投票人,请看看我更新的答案是否不那么令人反感。@PhilippWendler the Javadoc恰恰允许此代码,这意味着需要信号量实现在其中正确运行。您可以发布这方面的其余代码吗?因此,我们可以清楚地知道你想要实现什么。谢谢你,现在更清楚了,不要破坏你自己的帖子。你可以删除它们。
boolean wasAcquired = false;
try {
sem.acquire();
wasAcquired = true;
// crit sect
} catch (InterruptedException e) {
Thread.currentThread.interrupt();
} finally {
if (wasAcquired)
sem.release();
}
boolean acquired = false;
try {
lock.acquire();
acquired = true;
// critical section
} catch (InterruptedException e) {
// do anything
} finally {
if (acquired) {
lock.release()
}
}