【问题标题】:Java threads and synchronized blocksJava 线程和同步块
【发布时间】:2011-07-14 18:47:19
【问题描述】:

假设我在某个线程内执行synchronized 代码块,在synchronized 块内我调用一个方法,该方法生成另一个线程来处理需要与第一个方法相同的锁的同步代码块。所以在伪Java代码中:

public void someMethod() {
  synchronized(lock_obj) {
    // a whole bunch of stuff...

    // this is the last statement in the block
    (new Thread(someOtherMethod())).start();
  }
    // some more code that doesn't require a lock
}

public void someOtherMethod() {
  // some setup code that doesn't require a lock

  // return the stuff we want to run in another thread
  // that does require a lock
  return new Runnable() {
    @Override
    public void run() {
      synchronized(lock_obj) {
        // some more code
      }
    }
  };
}

我不知道如何理解该代码。我写的东西合法吗?从语法上看,我没有看到任何问题,但我不确定如何通过这样的代码进行推理。那么当我执行someOtherMethod() 以创建Runnable 的实例时,return 语句之前的代码会在什么样的范围内运行?它是否作为第一个同步块的一部分执行?假设还有一些其他线程也在工作,可能需要锁定lock_obj

【问题讨论】:

    标签: java multithreading concurrency deadlock synchronized


    【解决方案1】:

    在创建 runnable 和线程期间您仍然持有锁,但是在您调用 start 之后和线程实际拾取之前,您正在放弃锁。新线程将不得不与其他线程竞争锁。

    【讨论】:

      【解决方案2】:

      这段代码没有错。在someOtherMethod() 的return 语句之前,代码在someMethod() 的同步块中运行。新线程启动后,它将阻塞run() 方法内的synchronized 语句,直到它获得lock_obj 上的锁定(最早,每当someMethod() 退出其同步块时)。

      【讨论】:

      • 只是添加了一些可能会遗漏的东西—— someMethod() 中的同步块在 start() 被调用后立即退出,并且新线程正在并行执行。这似乎是造成 OP 困惑的原因。
      • @AbrahamPhilip - 我不会那样说的。当调用start() 时,同步块退出。 (它确实会在很短的时间内退出,因为对 start() 的调用恰好是同步块中的最后一条语句。)相反,调用 start() 会启动另一个线程的执行(开始时没有持有监视器),正在运行someOtherMethod() 返回的Runnable 中的代码。该其他线程需要等待someMethod() 中的块退出,然后才能进入自己的同步块。
      • 对不起,你说得对。让我换个说法,“就在” start() 被调用之后。我只是想强调这一点,因为 OP 想知道第二个线程的可运行对象是否在第一个同步块内执行(作为答案,这里错误地声称 stackoverflow.com/a/5295252/3000919)。我相信你的评论很好地解释了这一点,谢谢:)
      【解决方案3】:

      如果首先调用 someMethod(),则它是典型的死锁示例。

      我写的东西合法吗?
      ---- 是的,它在语法上是完全合法的。

      那么当我执行 someOtherMethod() 以创建 Runnable 的实例时,return 语句之前的代码在什么范围内运行? ----如果 someOtherMethod() 是从 someMethod() 中调用的,那么它在 someMethod() 方法的同步块的范围内。

      【讨论】:

      • 为什么会出现死锁? Thread.start 立即返回,此时 lock_obj 上的锁被释放,此时返回的 Runnable 要么获取锁,要么等待其他线程释放它。
      • 同意@davidk01 这不是死锁。如果是的话,它当然不是一个“经典”的例子。只是为了进一步了解,即使没有线程启动,在 java 中调用一个在线程已经持有的同一个锁上同步的方法也不会阻塞,因为调用者已经拥有锁。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-04-30
      • 2013-03-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多