Я запускал этот фрагмент кода 30 раз.
Запустите его еще семь миллиардов раз на каждую возможную комбинацию ОС и оборудования и сообщите о результатах. 30 очень низкое значение навсегда.
Почему "всегда второй, но почему?" всегда второй на консоли?
Сколько ядер у вас есть? Большинство планировщиков потоков предпочитают текущий запущенный поток по сравнению с вновь порожденным, особенно на одноядерных, и предпочитают синхронизировать потоки между ядрами в максимально позднюю точку (объект потока и System.out должны передаваться между потоками ОС ).
Учитывая, что многопоточность не является детерминированной, и большинство ОС не гарантирует честность и своевременность, это ни в коем случае не ошибка, что она ведет себя таким образом.
Если вы хотите явно упорядочить потоки, вам следует использовать либо синхронизированные блоки, либо более мощные классы в java.util.concurrent. Если вы хотите недетерминированное поведение, но разрешаете запуск другого потока, вы можете дать подсказку планировщику, используя Thread.yield()
.
public static void main ( String [] args )
{
FirstThreadBug t = new FirstThreadBug();
System.out.println ( "always first" );
t.start();
yield();
System.out.println ( "always second but why?" );
}