【问题标题】:What happens to the lock when thread crashes inside a Synchronized block?当线程在同步块内崩溃时,锁会发生什么?
【发布时间】:2012-09-20 22:23:10
【问题描述】:

假设 Thread-1 在对象上同步

synchronize(object){
  //statement1
  //statement2
  //statement3
}

如果 Thread-1 在 statement2 上崩溃,对象上的锁会发生什么情况,当这种情况发生时,JVM 会自动释放 Thread-1 上的锁吗?因为否则如果 Thread-2 正在等待释放对象上的锁并且 Thread-1 崩溃,那么 Thread-2 将永远等待。

【问题讨论】:

  • 可以肯定的是,线程不会“崩溃”。他们可以抛出异常,但不会像 C 那样进行段错误或核心转储。您可能会遇到 [非常] 奇怪的 JVM 错误,但在这种情况下,整个 Java 进程都会崩溃。这种情况极少发生。

标签: java multithreading synchronization


【解决方案1】:

定义在JLS #14.19:

synchronized ( Expression ) Block

如果块的执行由于任何原因突然完成,则监视器被解锁并且同步语句由于同样的原因突然完成。

【讨论】:

  • 非常感谢@assylias 和所有其他人(@Tudor、@dty 和@pst)的回复。
  • @assylias 如果我们使用 java.util.concurrent 包的 Lock.lock() API,并且我们没有按照建议在 finally 块中释放锁,而是在 try 块中释放它并且线程崩溃中间是否也会自动释放锁。
  • @legend 不,如果你不解锁它,它将保持锁定状态 - the javadoc 明确指出锁应该在 finally 块中解锁,除非你引入一种机制来解锁锁如果有例外 - 但这更复杂。
  • @assylias JLS 是否提供有关同步块 s.t 的保证。如果一个线程获得了锁,那么该线程将完全执行同步块并且它不能被线程调度器取消调度?
  • @YugSingh 我不确定 - 您可以将其作为一个单独的问题提出,我相信您会得到一些答案。
【解决方案2】:

你应该想到synchronized 块:

synchronized(lock) {
   // code
}

相当于(伪代码):

lock.acquire();
try {
   // code
} finally {
   lock.release();
}

因此,无论代码段发生什么,锁都会被释放。

【讨论】:

  • 您假设 finally 将运行。如果线程由于某种原因崩溃会发生什么。
  • @Geek:AFAIK 不执行finally 块的唯一方法是如果整个JVM 崩溃,但在这种情况下释放锁变得无关紧要。
  • 我想我也同意你的看法。这可能是因为 finally 的实现方式。假设 finally 作为一个微型函数被复制到堆栈上,这看起来是一个可行的情况。但是,如果我完全转储或丢弃线程堆栈,我认为 finally 根本无法运行。我不是在挑战你的想法,只是想更多地理解这一点:-)
【解决方案3】:

是的,监视器(非锁定)将被释放。

如果您想阅读,Java VM 规范将对此进行具体说明。

JVM 规范中的确切参考可以在section 2.11.10 中找到

在调用设置了 ACC_SYNCHRONIZED 的方法时,执行线程进入监视器,调用方法本身,然后退出监视器,无论方法调用正常完成还是突然完成。在执行线程拥有监视器期间,没有其他线程可以进入它。如果在调用同步方法期间抛出异常并且同步方法不处理异常,在异常被(重新)抛出同步方法之前自动退出该方法的监视器。

【讨论】:

  • 不过,这技术上是在谈论同步方法。
  • 正常执行或异常(Catched/Uncatched)发生时会出现这种情况。当线程由于覆盖内存位置而被杀死时会发生什么。
猜你喜欢
  • 2014-07-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-08-20
  • 2016-12-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多