Могу ли я установить количество потоков/процессоров, доступных для виртуальной машины Java?

Я хотел бы ограничить количество потоков/процессов, доступных для Java VM, подобно тому, как вы устанавливаете доступную память. Я хотел бы иметь возможность указать его, чтобы просто использовать 1 поток или произвольное число.

ПРИМЕЧАНИЕ. Я не могу установить его в коде, поскольку код, который я хотел бы ограничить, - это библиотека, в которой я не могу изменить источник. Таким образом, это должен быть жесткий колпак, наложенный на уровень виртуальной машины. (Или если вы могли бы наложить ограничение потока на само приложение, которое могло бы переопределять библиотеки?)

ПРИМЕЧАНИЕ 2. Целью этого является тест производительности, чтобы дросселировать библиотеку, которую я хочу протестировать, чтобы увидеть, насколько хорошо она будет работать, когда у нее будет доступ к процессорам с разными номерами/потоками.

Спасибо!

Ответ 1

Нет никакого флага VM или свойства для управления количеством доступных на Java процессоров, т.е. возвращаемого Runtime.availableProcessors().

В Windows и Solaris, если вы установите маску сродства процесса, это также повлияет на Runtime.availableProcessors(). Это не работает в Linux, но см. JDK-6515172. К сожалению, исправление предназначено только для Java 10, но предлагаемый патч включен в обсуждение ошибок.

Существует также работа для Linux с использованием патча LD_PRELOAD или трюка на уровне ОС, см. подробности в этом вопросе.

Ответ 2

Я предлагаю вам реализовать и установить собственный SecurityManager, который отслеживает количество созданных потоков и генерирует ошибку при достижении максимума.

В соответствии с принятым ответом на этот вопрос, RuntimePermission с целью "modifyThreadGroup" проверяется каждый раз при создании/запуске нового потока.

Обновление

Первый подход SecurityManager может быть таким:

class MySecurityManager extends SecurityManager
{
    private final int maxThreads;

    private int createdThreads;

    public MySecurityManager(int maxThreads)
    {
        super();
        this.maxThreads=maxThreads;
    }

    @Override
    public void checkAccess(Thread t)
    {
        // Invoked at Thread *instantiation* (not at the start invokation).
        super.checkAccess(t);

        // Synchronized to prevent race conditions (thanks to Ibrahim Arief) between read an write operations of variable createdThreads:
        synchronized(this)
        {
            if (this.createdThreads == this.maxThreads)
            {
                throw new Error("Maximum of threads exhausted");
            }
            else
            {
                this.createdThreads++;
            }
        }
    }
}

В корне необходимо провести дополнительное тестирование, чтобы гарантировать, что системные потоки всегда разрешены. И оставайтесь, что этот алгоритм не уменьшает счетчик, когда заканчивается поток.

Ответ 3

Если вы используете linux, просто запустите панель запуска java в numactl/taskset. Это позволяет JVM создавать любое количество потоков, но планирует их на фиксированное количество физических ядер.

Аналогичные инструменты доступны и для других ОС.

Ответ 4

Попробуйте запустить вашу программу с "сродством" для пользователей Windows.

Например: вместо запуска "java Test" вы должны запустить: "start/affinity 1 java Test", когда вам нужно 1 ядро; "start/affinity 3 java Test", когда вам нужно 2 ядра;... Используемый параметр должен иметь следующую форму:

https://blogs.msdn.microsoft.com/santhoshonline/2011/11/24/how-to-launch-a-process-with-cpu-affinity-set/

Вы можете использовать "System.out.println(Runtime.getRuntime(). AvailableProcessors()); для проверки.

Ответ 5

В качестве последнего средства я мог бы установить сходство Java VM в диспетчере задач, чтобы использовать только 1 (или более) CPU (s). (это, конечно же, позволит использовать несколько потоков на 1 процессоре, но, вероятно, это самое близкое к тому, что я хотел, если у кого-то еще нет лучших идей)

Ответ 6

Проблема ограничений ЦП в JVM была решена в Java 10 и перенесена в Java 8 из сборки 8u191:

-XX:ActiveProcessorCount=2