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

21,579

Solution 1

The problem of CPU limits in JVM was solved in Java 10 and is backported to Java 8 from build 8u191:

-XX:ActiveProcessorCount=2

Solution 2

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.

Solution 3

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.

Solution 4

Before JDK 8u191, there was no VM flag or a property to control number of CPUs available to Java, i.e. 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

Solution 5

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.

Share:
21,579
Martin K
Author by

Martin K

Updated on February 15, 2021

Comments

  • Martin K
    Martin K over 3 years

    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!

  • Martin K
    Martin K over 8 years
    The answer below the 'accepted' one by 'alphaloop' says that it is actually not possible to do it via SecurityManager? In any case I didn't want to just monitor it, I wanted to specify a cap so that it is throttled to a specific level so that I can see how well the library performs under different conditions.
  • Little Santi
    Little Santi over 8 years
    I see. I've included in my answer and tested myself a SecurityManager that limits the number of threads. You could start by this, and go on on testing.
  • Ibrahim Arief
    Ibrahim Arief over 8 years
    This code has the potential for a race conditions to mess up with the check and increment. At the very least, use this.createdThreads > this.maxThreads instead of direct equivalency. At best, refactor the code to use better concurrency mechanisms.
  • Little Santi
    Little Santi over 8 years
    @Ibrahim Arief Right. I've updated my post, although a new synchronization will reduce performance a little. Thanks.
  • apangin
    apangin over 8 years
    Unfortunately HotSpot JVM does not respect taskset on Linux (bug JDK-6515172). JVM will still think all processors are available, resulting in excessive number of GC threads, Compiler threads and the value of Runtime.availableProcessors() that applications and libraries may depend on, e.g. the size of default ForkJoinPool is also based on availableProcessors.
  • the8472
    the8472 over 8 years
    @apangin, Compiler/GC threads can be tuned, the rest doesn't seem like insurmountable obstacles either. Might still be good enough for testing.
  • Jasper Siepkes
    Jasper Siepkes over 4 years
    This answer is no longer valid since the -XX:ActiveProcessorCount flag was also backported to OpenJDK 8.
  • Little Santi
    Little Santi about 4 years
    @SimonLogic In fact, I do not (read the note at the end). To achieve an accurate, up-to-date count of live threads, I guess a ReferenceQueue must be included.
  • Khanna111
    Khanna111 about 3 years
    will work for the thread count in the default thread pools. Will not work to limit the CPUs though.
  • keturn
    keturn about 2 years
    The bug apangin linked is marked as resolved for Java 9, and if I'm reading it correctly, was backported to Java 1.8 as well. So hopefully this works for currently supported Java versions?