notifyAll()分析时调用的数量差异

时间:2011-05-03 11:49:40

标签: java multithreading profiling jvmti

我已经使用JVMTI实现了一个简单的探查器,以在wait()notifyAll()上显示调用。作为测试用例我正在使用。 producer consumer example of Oracle。我有以下三个事件:

  • 调用notifyAll()
  • 调用wait()
  • 等待()离开

wait()调用及其离开时,使用事件MonitorEnterMonitorExit对其进行了分析。当退出名为notifyAll()的方法时,将对notifyAll调用进行分析。

现在我有以下结果,第一个来自分析器本身,第二个来自Java ,我在其中放置了相应的System.out.println语句

    // Profiler:
    Thread-1 invoked notifyAll()
    Thread-0 invoked notifyAll()
    Thread-0 invoked notifyAll()
    Thread-0 invoked notifyAll()
    Thread-0 invoked notifyAll()
    Thread-0 invoked notifyAll()
    Thread-1 invoked notifyAll()
    Thread-1 invoked notifyAll()
    Thread-1 invoked notifyAll()
    Thread-1 invoked notifyAll()
    Thread-1 invoked notifyAll()
    Thread-1 invoked notifyAll()
    Thread-1 invoked notifyAll()
    Thread-1 invoked wait()
    Thread-1 left wait()
    Thread-1 invoked notifyAll()
    Thread-1 invoked wait()
    Thread-1 left wait()
    Thread-1 invoked notifyAll()
    Thread-1 invoked wait()
    Thread-1 left wait()
    Thread-1 invoked notifyAll()

    // Java:
    Thread-0 invoked notifyAll()
    Thread-1 invoked notifyAll()
    Thread-0 invoked notifyAll()
    Thread-1 invoked notifyAll()
    Thread-0 invoked notifyAll()
    Thread-1 invoked wait()
    Thread-1 invoked notifyAll()
    Thread-0 invoked notifyAll()
    Thread-1 invoked wait()
    Thread-1 invoked notifyAll()
    Thread-0 invoked notifyAll()
    Thread-1 invoked wait()
    Thread-1 invoked notifyAll()

是否有人解释这种差异来自何方? notifyAll()被召唤了很多次。我被告知这可能是由于Java请求对操作系统的误报。

它发送给操作系统的notifyAll()请求,并发送了一个误报响应,似乎请求是成功的。由于通过分析方法调用而不是notifyAll来记录MonitorEnter,因此可以解释为什么在等待时不会发生这种情况。

我忘了说,我没有单独运行程序,两个日志来自同一个执行。

有条件的信息

最初作为答案添加,转移到extraneon的问题:

我想我发现了附加的notifyAll的部分来自哪里,我添加了调用notifyAll的方法上下文的分析:

723519: Thread-1 invoked notifyAll() in Consumer.take
3763279: Thread-0 invoked notifyAll() in Producer.put
4799016: Thread-0 invoked notifyAll() in Producer.put
6744322: Thread-0 invoked notifyAll() in Producer.put
8450221: Thread-0 invoked notifyAll() in Producer.put
10108959: Thread-0 invoked notifyAll() in Producer.put
39278140: Thread-1 invoked notifyAll() in java.util.ResourceBundle.endLoading
40725024: Thread-1 invoked notifyAll() in java.util.ResourceBundle.endLoading
42003869: Thread-1 invoked notifyAll() in java.util.ResourceBundle.endLoading
58448450: Thread-1 invoked notifyAll() in java.util.ResourceBundle.endLoading
60236308: Thread-1 invoked notifyAll() in java.util.ResourceBundle.endLoading
61601587: Thread-1 invoked notifyAll() in java.util.ResourceBundle.endLoading
70489811: Thread-1 invoked notifyAll() in Consumer.take
75068409: Thread-1 invoked wait() in Drop.take
75726202: Thread-1 left wait() in Drop.take
77035733: Thread-1 invoked notifyAll() in Consumer.take
81264978: Thread-1 invoked notifyAll() in Consumer.take
85810491: Thread-1 invoked wait() in Drop.take
86477385: Thread-1 left wait() in Drop.take
87775126: Thread-1 invoked notifyAll() in Consumer.take

但是,即使没有这些外部调用,也会有很多notifyAll调用在printf调试中没有出现。

2 个答案:

答案 0 :(得分:4)

我花了一些时间分析Oracle提供的Producer-Consumer示例和您的输出(探查器和Java程序)。除了几个意外的notifyAll()

之外,你的输出还有一些奇怪的东西
  1. 我们应该期望wait()方法执行4次(生产者操作的String数组有4个元素)。您的探查器的结果显示它只执行 三次。

  2. 另一件很奇怪的事情是分析器输出中的线程编号。该示例有两个线程,但是您的探查器会在一个线程中执行所有代码,即Thread-1,而Thread-0只执行notifyAll()

  3. 从并发的角度和语言角度对所提供的示例代码进行了正确编程:wait()notifyAll()采用同步方法,以确保对监视器的控制;等待条件在while循环内,通知正确放置在方法的末尾。但是,我注意到catch (InterruptedException e)块为空,这意味着如果正在等待的线程被中断,则将执行notifyAll()方法。这可能是导致多个意外notifyAll()

  4. 的原因

    总之,如果不对代码进行一些修改并执行一些额外的测试,就不容易找出问题的来源。

    作为旁注,我会留下这个链接Creating a Debugging and Profiling Agent with JVMTI给那些想要玩JVMTI的好奇人。

答案 1 :(得分:1)

如果您的代码中存在竞争条件,则分析器可能会使代码速度变慢,以显示或隐藏代码中的错误。 (我喜欢在探查器中运行我的程序,只是为了显示竞争条件。)

由于notifyAll()只会通知wait()线程,因此在notifyAll()可能导致错过通知后调用wait()。即它的无国籍,它不知道你以前叫过通知。

如果你放慢你的应用程序的速度,那么notifyAll()可以延迟到wait()开始之后。