简体   繁体   中英

Can I set the number of Threads/CPUs available to the Java VM?

I would like to limit the number of threads/processes available to the Java VM, similar to how you set the available memory. I would like to be able to specify it to just use 1 thread, or an arbitrary number.

NOTE: I cannot set it in the code, as the code that I would like to limit is a library where I cannot modify the source. So it must be a hard cap imposed on the level of the virtual machine. (Or if you could impose a thread limit on the application itself that could override libraries?)

NOTE2: The purpose of this is a performance test, to throttle a library I want to test, to see how well it would perform when it has access to a different number CPUs/Threads.

Thanks!

JVM 中的 CPU 限制问题在 Java 10 中得到解决,并从 build 8u191 向后移植到 Java 8:

-XX:ActiveProcessorCount=2

Before JDK 8u191, there was no VM flag or a property to control number of CPUs available to Java, ie what Runtime.availableProcessors() returns.

On Windows and Solaris if you set the process affinity mask, it will also affect Runtime.availableProcessors() . This did not work on Linux though, see JDK-6515172 .

There is also a work around for Linux using LD_PRELOAD patch or a OS-level trick, see details in this question .

UPDATE

  • JVM now respects taskset on Linux since JDK 8u121, see JDK-6515172
  • Since JDK 8u191, there is a JVM flag -XX:ActiveProcessorCount=nn to override the number of CPUs visible to the JVM, see JDK-8146115

If you're on linux simply wrap the java launcher in a numactl / taskset command. That allows the JVM to spawn any number of threads but schedules them on a fixed amount of physical cores.

Similar tools are available for other OSes too.

Try to run your program with "affinity" for windows user.

For Example: instead of running "java Test", you should run: "start /affinity 1 java Test" when you need 1 core; "start /affinity 3 java Test" when you need 2 core; .... The parameter used should follow this form:

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

You can use "System.out.println(Runtime.getRuntime().availableProcessors()); to check.

I suggest you could implement and install your own SecurityManager which tracks the number of created threads and throws an Error when the maximum is reached.

According to the accepted answer to this question , a RuntimePermission with "modifyThreadGroup" target is checked every time a new thread is created/started.

Update

A first approach of the SecurityManager could be like this:

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++;
            }
        }
    }
}

Of corse, further testing must be done to gurantee that system threads are always allowed. And remain that this algorithm does not decrement the count when a thread ends.

As a last resort, I could set the Java VM's affinity in task manager to only use 1 (or more) CPU(s). (this will of course still allow multiple threads on 1 CPU, but it's probably the closest thing to what I wanted if noone else has any better ideas)

To test this, I used the a later java version (java version "14.0.2" 2020-07-14) and this option:

-XX:ActiveProcessorCount=2

However, this would not restrict the JVM from using more than 2 processors . It would use more if available.

As per my understanding (of the docs ) and experimentation, this affects the calculation of the number of threads in a thread pool etc. But does NOT apply any restrictions on the number of cpus allocated to the process.

One way to restrict the cpu usage was to run the java process inside of a docker container and using the

"--cpus"

docker option.

This is what I use especially on Mac OS that has currently no supported utility to restrict cpus.

Another way is to use a OS specific utility such as taskset / isolcpus / cgroups (available on Linux).

So if the question is to limit the cpus used by the java process, then the ActiveProcessorCount option is useless on its own. Run it inside the docker container or use an OS specific wrapper that deals with allocation / restriction of cpu or other resources.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM