Java线程调度:比处理器更繁忙的等待线程?

时间:2016-04-22 16:58:11

标签: java multithreading

我创建了一个测试Java Thread调度的小型虚拟程序:

  @Test
  public void testThreadScheduling() throws Exception {
    int nprocs = Runtime.getRuntime().availableProcessors();
    System.out.println(String.format("I have %s processors available", nprocs));

    // schedule more threads than I have processors
    for (int i = 0; i < nprocs + 5; i++) {
      final int thread = i;
      new Thread((() -> {
        System.out.println(String.format("Thread %s has been scheduled", thread));
        while (true) { /* busy wait */ }
      })).start();

      // wait a little before spawning the next thread
      Thread.sleep(100);
    }
  }

现在输出到(每次我运行它)完全相同:

I have 12 processors available
Thread 0 has been scheduled
Thread 1 has been scheduled
Thread 2 has been scheduled
Thread 3 has been scheduled
...
Thread 15 has been scheduled
Thread 16 has been scheduled

我认为可能发生这种情况的原因是因为操作系统(或JVM)正在抢占已经超过其量子的线程,但我的问题是它使用的策略是什么,是它是正在进行抢占的操作系统还是JVM?

关于发动机罩下可能发生的事情的任何更多细节将特别感谢!

java版本&#34; 1.8.0_40&#34;
Java(TM)SE运行时环境(版本1.8.0_40-b26)
Java HotSpot(TM)64位服务器VM(版本25.40-b25,混合模式)

1 个答案:

答案 0 :(得分:2)

这绝对是操作系统处理线程调度的工作。实际上如何完成调度取决于操作系统,在某些情况下,如果操作系统允许用户为线程优先级设置标志,则由用户决定。

如果您对量化这种情况的方式感兴趣,可以测量在for循环结束时经过的实际时间,并查看每次迭代是否等待的时间明显长于第12个线程启动后的100 ms休眠时间。另一种选择可能是使用以下代码片段来获取JVM的ThreadMXBean实例并仔细查看其线程争用统计信息:

ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
threadMXBean.setThreadContentionMonitoringEnabled(true);

//Then, use specific thread IDs to get contention info periodically:

int threadID = ... //you can use getId() on each thread you created
ThreadInfo info = threadMXBean.getThreadInfo(threadID);
info.getBlockedTime(); //returns millis
info.getWaitedTime(); //returns millis

如果在epoch millis中跟踪线程的启动时间,可以将它与最后两种方法结合使用,以了解线程花在CPU上实际运行的时间与等待其他线程的时间。我认为此ThreadInfo对象提供的度量与使用synchronized关键字和Java Lock对象严格相关,因此可能无法准确评估您的O / S如果您的线程未被阻止但被操作系统抢占,则会执行此操作。您可以计算总非等待/非阻塞时间,并将其与线程实际可用的运行时间进行比较,差异将为您提供线程被O / S预占的总时间。

我怀疑这可能不会给你你正在寻找的详细程度,但我认为这与你在没有编写一堆原生的,特定于操作系统的代码和使用JNI的情况下的距离非常接近在Java程序中访问它。