我创建了一个测试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,混合模式)
答案 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程序中访问它。