Java尝试终极竞争条件?

Jxt*_*tps 7 java exception-handling thread-safety race-condition

许多Java资源使用示例如下所示:

Resource r = openResource(); 
try { 
  // use resource
} finally { 
  r.close();
}
Run Code Online (Sandbox Code Playgroud)

声明r必须在try-clause 之外才能在finally-clause中显示,但这也使得它看起来像是一个潜在的竞争条件:如果在openResource()-call和进入try-clause 之间存在线程中断怎么办?

这是否意味着在该场景中资源实际上并未关闭?

或者Java是否保证try-finally封面r"完全",尽管语法看起来不像?

或者我必须写:

Resource r = null;  
try { 
  r = openResource();
  // use resource
} finally { 
  if (r != null) r.close();
}
Run Code Online (Sandbox Code Playgroud)

为了防止线程中断?

Jon*_*eet 4

如果在 openResource() 调用和进入 try 子句之间发生线程中断怎么办?

然后线程不会抛出异常,InterruptedException直到遇到一些阻塞调用。在进入try块之前这种情况不会发生,因为假设该方法实际返回,就不会再有任何阻塞调用。从文档中InterruptedException

当线程正在等待、休眠或以其他方式占用,并且线程在活动之前或活动期间被中断时抛出。有时,一个方法可能希望测试当前线程是否已被中断,如果是,则立即抛出此异常。

请注意,即使您确实获取放入try块内,这并不能真正防止任何本来存在的竞争条件 - 因为您将依赖于首先返回的方法或构造函数。如果异常可以在方法/构造函数返回之后发生,为什么它不能返回之前发生,而是在获取资源之后发生?如果发生这种情况,你就没有什么可以打电话close的了...

我仍然建议在 Java 7 中使用 try-with-resources 语句,但是如果您查看JLS 第 14.20.3.1 节,您会发现扩展就像您的第一段代码:

基本 try-with-resources 语句的含义:

try ({VariableModifier} R Identifier = Expression ...)
    Block
Run Code Online (Sandbox Code Playgroud)

由以下对局部变量声明和 try-catch-finally 语句的翻译给出:

{
    final {VariableModifierNoFinal} R Identifier = Expression;
    Throwable #primaryExc = null;

    try ResourceSpecification_tail
        Block
    catch (Throwable #t) {
        ...
        #primaryExc = #t;
        throw #t;
    } finally {
       ...
    }
}
Run Code Online (Sandbox Code Playgroud)