Java尝试终极竞争条件?

时间:2014-08-11 20:12:13

标签: java exception-handling thread-safety race-condition

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

Resource r = openResource(); 
try { 
  // use resource
} finally { 
  r.close();
}

r的声明必须在try - 子句之外,才能在finally - 子句中看到,但这也使得它看起来像是一种潜在的竞争条件: 如果在openResource() - 调用和输入try - 条款之间存在线程中断,该怎么办?

这是否意味着资源 实际上在那种情况下无法关闭?

或者Java保证try-finally覆盖r“完全”,尽管语法看起来不是这样吗?

或者我必须写:

Resource r = null;  
try { 
  r = openResource();
  // use resource
} finally { 
  if (r != null) r.close();
}

为了防止线程中断?

4 个答案:

答案 0 :(得分:4)

这些Java资源使用示例可以像您在r初始设置为null时所提供的示例一样编写,但是如果它们使用Java 7 try-with-resources语法(假设{{1}实现AutoCloseable):

Resource

然后它们将等同于第一个示例,其中try (Resource r = openResource()) { // use resource } 块之前调用openResource()Java Language Specification for the try-with-resources statement定义语义等同于在块之前使用初始化程序分配变量,然后输入try块。

在输入try-catch-finally块之前发生异常似乎存在问题。但问题在很大程度上是理论上的。如果try正常返回并且在openResource()的赋值和try块的开头之间没有介入语句,则不太可能,但不是不可能,其他一些线程在{ {1}}阻止开始,但即使这样,当你的线程再次开始运行时,它会毫无意外地进入r块。如果另一个线程做了导致JVM关闭的事情,比如调用try,那么通常不需要担心关闭资源。甚至这种情况也不大可能。

另一方面,如果打开资源时出现问题,可能会抛出try,这会阻止System.exit被分配。

答案 1 :(得分:4)

  

如果在openResource()之间存在线程中断 - 调用并输入try-clause会怎么样?

然后线程不会抛出InterruptedException,直到它遇到一些阻塞调用。这在进入try块之前不会发生,因为不再阻塞调用,假设方法实际返回。来自InterruptedException的文档:

  

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

请注意,即使你将收购放在try区块内,这也不能真正防止任何原本存在的竞争条件 - 因为你依赖于方法或构造函数首先返回。如果在方法/构造函数返回之后发生异常,那么为什么它不会在返回之前发生,但是在获取资源之后?如果发生这种情况,您无法在{... 1}上调用{<1}}。

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

  

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

close
     

通过以下转换给出局部变量声明和try-catch-finally语句:

try ({VariableModifier} R Identifier = Expression ...)
    Block

答案 2 :(得分:3)

没有潜在的竞争条件。您在调用getResource期间遇到异常,或者它可能返回null - 但是没有竞争条件。如果您的线程被中断,您可能会收到InterruptedException,但这会阻止您进入尝试块。

答案 3 :(得分:0)