Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/309.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 为什么这个同步块似乎需要很长时间才能获得锁?_Java_Android_Multithreading_Synchronized - Fatal编程技术网

Java 为什么这个同步块似乎需要很长时间才能获得锁?

Java 为什么这个同步块似乎需要很长时间才能获得锁?,java,android,multithreading,synchronized,Java,Android,Multithreading,Synchronized,我不熟悉java中的多线程,我有一个问题,有些人可能会觉得很琐碎 我必须调试一段第三方代码,我需要一些基本信息,知道在哪里查找问题,因为代码非常大 当以下代码运行时: public void method() { long startTime = System.currentTimeMillis(); synchronized (obj) { log( "time:" + System.currentTimeMillis() - startTime + " ms"

我不熟悉java中的多线程,我有一个问题,有些人可能会觉得很琐碎

我必须调试一段第三方代码,我需要一些基本信息,知道在哪里查找问题,因为代码非常大

当以下代码运行时:

public void method()
{
   long startTime = System.currentTimeMillis();
   synchronized (obj)
   {
      log( "time:" + System.currentTimeMillis() - startTime + " ms" );
      ...
   }
}
我得到:

11:13:12 - time: 3816 ms
...
11:14:14 - time: 0 ms
为什么要花这么长时间(3816毫秒)才能获得对象的锁? 我应该去哪里看?例如,我可以想象一个可能的答案是寻找获得“obj”锁的代码,即块,例如:

synchronized (obj) { ... }

或者,在对象“obj”上进行任何没有“synchronized”的修改是否也可以锁定该对象?

您需要检查以下内容:

  • 在您的obj类中是否有任何方法/块,这些方法/块是在此基础上同步的。如果是,那么必须有多个线程,其中一个是您上面的代码,而另一个可能使用相同obj的方法
  • 你都在哪里分享obj?如果它是由多个类共享的,那么检查是谁锁定了同一个对象
    • 作为jdk一部分的实用程序可以帮助实现这一点。
      -l
      (长列表)选项将打印各个线程持有的所有锁。如果您可以在问题发生时捕获程序,那么您可以找到另一个持有锁的线程。您可以通过查找线程,查看它正在等待的条件对象,然后在堆栈的其余跟踪中搜索该条件对象来实现这一点


      这有关于如何查看线程转储的更详细信息。

      如果线程需要那么长时间才能获得锁,那是因为当前有其他人持有它

      你应该注意两件事:

    • 在同一对象或对其的其他引用上同步的代码块(称为):

    • 在对象本身内部

      假设
      obj
      属于
      MyObject
      类型,那么您应该寻找如下方法:

      public class MyObject{
          public synchronized void myMethod() {
           ...
          }
      }
      
      因为它们本质上和

      public class MyObject{
          public void myMethod() {
              synchronized (this) {
               ...
              }
          }
      }
      
      因此,如果一个线程正在执行
      obj.myMethod()
      ,那么想要进入
      synchronized(obj)
      块的线程将不得不等待,因为它们都锁定在同一个对象上。顺便说一下,这就是为什么我强烈建议不要使用同步方法语法,总是锁定私有(或受保护)类成员的原因

    • 如果另一个线程当前正在此类块中执行代码,则当前线程将被锁定,直到另一个线程完成


      您可以使用或获取所有线程的当前执行状态及其所持有的锁的快照。如果您使用的是android,请参阅如何在那里获取线程转储的答案。

      这是您获得的第一个日志吗?@CommuSoft是这是我获得的第一个日志got@fge对象是一个复杂的对象。它被用在许多不同的班级,做许多不同的事情。你能解释一下你为什么问这个问题,这样我才能给你一个准确的答案吗?@CommuSoft如果这是Oracle的JVM,因此是热点,那么优化只有在10000次执行之后才会开始触发;因此,我怀疑JIT是否是你在锁着的浴室门外等待的答案。为什么在那里花了这么长时间?这个问题的答案绝对与门锁的质量无关,而与房间里的人有关。记住,使用锁的建议是:(1)不要花任何时间在锁上,以避免争用;(2)拥有尽可能少的锁,以避免死锁错误。聪明的读者会注意到,这两条极好的建议实际上是对立的,这会在尝试遵循时产生问题。有趣的游戏,并发;赢得比赛的唯一方法是不要玩。你还应该看看
      obj
      是否不仅与
      synchronized
      一起使用,还与
      notify
      lock
      一起使用,它们可以进行交互。应该避免混合使用这两种同步模式,但在调试第三方代码时,您应该做好最坏的准备。是的,但请注意,如果没有通知,OP的输出将永远不会打印任何内容。而且,很明显,如果您使用synchronize,那么您将使用notify/wait,但正如您所说的,是的,不能确定。@dritan是的,当然。我现在已经添加了这个细节。为了避免这个问题,我强烈建议您避免声明同步方法,而是在私有类成员上同步。您可以使用jvisualvm的Threads选项卡或Jstack拍摄所有线程的当前执行状态及其持有的锁的快照。==>我正在android上开发。你对这种环境有什么建议吗?@dritan我没有,但堆栈溢出有-只是注意到答案的第2点是相关的。其他线程调用了其他同步方法。问题标记为[android],因此JDK实用程序可能不是最有用的。@fadden发布此答案时,它没有标记为“android”
      public class MyObject{
          public void myMethod() {
              synchronized (this) {
               ...
              }
          }
      }