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

Kon*_*che 11 java multithreading profiling jvmti

我实现了一个简单的探查与JVMTI显示的调用wait()notifyAll().作为测试用例我正在使用.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()
Run Code Online (Sandbox Code Playgroud)

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

notifyAll()它发送到操作系统和假阳性响应请求被发送,其中,好像请求是sucessfull.因为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
Run Code Online (Sandbox Code Playgroud)

但是,即使没有这些外部调用,也会有一些在printf调试中没有显示的notifyAll调用.

bac*_*hus 4

我花了一些时间分析Oracle 提供的生产者-消费者示例以及您的输出(分析器和 Java 程序)。除了几个意外的情况之外,您的输出中还有一些奇怪的事情notifyAll()

  1. 我们应该期望 wait() 方法执行 4 次(String生产者操作的数组有 4 个元素)。分析器的结果显示它只执行了 3 次。

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

  3. 提供的示例代码从并发角度和语言角度正确编程:wait()并且notifyAll()采用同步方法以确保对监视器的控制;等待条件位于while循环内,通知正确放置在方法的末尾。但是,我注意到该catch (InterruptedException e)块是空的,这意味着如果正在等待的线程被中断,该notifyAll()方法将被执行。这可引起了几人的始料未及notifyAll()

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

作为旁注,我将把这个链接“使用 JVMTI 创建调试和分析代理”留给那些想要使用 JVMTI 的好奇者。