В вашем примере каждый ЦП может запускать процесс одновременно, поэтому, если у вас есть только 4 процесса, у вас все хорошо.
Если вы хотите, чтобы ваша программа работала и в случае, когда процессов больше, чем процессоров, вам нужно нечто более сложное. В этом случае я бы порекомендовал вам взглянуть на среду параллелизма Java.
Для самого простого решения, когда у вас есть более 4 процессов, которые вы хотите запустить, я бы использовал ExecutorService.newFixedThreadPool (4) и добавил бы каждый процесс (как вызываемый) в результирующий пул потоков, используя любой invokeAll () или отправить ().
НО это не дает вам параллелизма между всеми запущенными процессами (он подхватит 5-й процесс только после завершения одного из первых 4 процессов). Если вы хотите, чтобы ваша программа работала как настоящая многопоточная ОС (где больше процессов может быть активнее, чем доступно ЦП), вам нужно добавить какой-то планировщик, который может назначать часть процесса на одном из доступных ЦП, затем (до того, как первый будет сделан) пусть другой процесс использует тот же самый ЦП для части своей работы и т. д. Так что он должен будет разрешить выполнение части процессов, затем выполнить часть одного или нескольких других процессов, затем позволить первые делают немного больше своей работы и т. д., пока не будут выполнены все процессы.
Тогда вашему симулятору также потребуется какой-то способ решить, когда процесс может быть «приостановлен» (то есть отложен планировщиком для последующего получения) ...