2016-04-22 3 views
2

Я создал небольшую фиктивную программу, которая проверяет Java планирования Тема:Планирование потоков Java: более занятые потоки ожидания, чем процессоры?

@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?

Более подробная информация о том, что может происходить под капотом, особенно ценится!


ява версия "1.8.0_40"
Java (TM) SE Runtime Environment (сборка 1.8.0_40-b26)
Java HotSpot (TM) 64-разрядный сервер VM (сборка 25,40-B25, смешанная mode)

ответ

2

Это определенно задача операционной системы для обработки планирования потоков. Как фактически выполняется планирование, до O/S, а в некоторых случаях до пользователя, если O/S позволяет пользователям устанавливать флаги для приоритета потока.

Если вы заинтересованы в количественном определении того, как это происходит, вы можете измерить фактическое время, прошедшее в конце вашего цикла for, и посмотреть, будет ли каждая итерация ждать значительно дольше, чем ваше 100-секундное спящее время после запуска 12-го потока , Другим вариантом может быть использовать следующий фрагмент кода, чтобы захватить ThreadMXBean экземпляр вашей JVM и просмотреть его нить статистику раздор

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 

Если следить за временем запуска вашего потока в эпоху Millis, вы можете использовать его в сочетании с эти последние два метода, чтобы узнать, сколько времени потраченный поток фактически работает на процессоре, и ожидает других потоков. Я думаю, что измерения, предоставленные этим объектом ThreadInfo, строго связаны с использованием ключевого слова synchronized и объектов Java Lock, однако это может быть не точная оценка того, что делает ваш O/S, если ваши потоки в противном случае разблокированы, освобожденный ОС. Вы можете рассчитать общее время ожидания и неблокирования и сравнить это с тем, сколько времени было фактически доступно для ваших потоков для запуска, и разница даст вам общее время, когда ваши потоки были предварительно упущены вашим O/S.

Я подозреваю, что это, вероятно, не дает вам уровня детализации, который вы ищете, но я думаю, что это примерно так же близко, как вы можете получить, не написав кучу родного, O/S-специфичного кода и используя JNI для доступа к нему в вашей программе Java.

+0

Хороший призыв к измерению времени, необходимого для планирования: после Thread 11 он перескакивает от 1 мс до ~ 15 мс, а затем продолжает увеличиваться по мере увеличения количества потоков! – Almog

+0

Похоже, что есть определенное увеличение времени планирования. Некоторое время можно было бы использовать для создания самого потока - вы можете рассмотреть возможность инициализации всех ваших потоков за пределами текущего цикла for и только вызов метода «start» в цикле. Таким образом, вы знаете, что на ваши измерения не влияет вызов конструктора. – CodeBlind

Смежные вопросы