我可以设置Java VM可用的线程/ CPU数量吗?

时间:2015-11-15 18:32:39

标签: java multithreading jvm

我想限制Java VM可用的线程/进程数,类似于设置可用内存的方式。我希望能够指定它只使用1个线程或任意数字。

注意:我无法在代码中设置它,因为我想限制的代码是一个我无法修改源代码的库。因此,它必须是强加于虚拟机级别的硬限制。 (或者,如果您可以对应用程序本身施加可以覆盖库的线程限制?)

注意2:这样做的目的是进行性能测试,以限制我想要测试的库,看看当它可以访问不同数量的CPU /线程时它的执行情况。

谢谢!

7 个答案:

答案 0 :(得分:2)

没有VM标志或属性来控制Java可用的CPU数量,即Runtime.availableProcessors()返回的内容。

在Windows和Solaris上,如果设置了进程关联掩码,它也会影响Runtime.availableProcessors()。但这在Linux上不起作用,请参阅JDK-6515172。不幸的是,修复程序仅针对Java 10,但建议的修补程序包含在错误讨论中。

使用LD_PRELOAD补丁或操作系统级技巧也可以解决Linux的问题,请参阅this question中的详细信息。

答案 1 :(得分:1)

我建议您可以实现并安装自己的SecurityManager,它跟踪创建的线程数,并在达到最大值时抛出错误。

根据this question的接受答案,每次创建/启动新线程时都会检查带有“modifyThreadGroup”目标的RuntimePermission

<强>更新

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

对于corse,必须进行进一步的测试以保证始终允许系统线程。并且当线程结束时,此算法不会减少计数。

答案 2 :(得分:1)

如果您使用Linux,只需将java启动器包装在numactl / taskset命令中即可。这允许JVM生成任意数量的线程,但是在固定数量的物理内核上调度它们。

其他操作系统也可以使用类似的工具。

答案 3 :(得分:1)

尝试为Windows用户使用“亲和力”运行程序。

例如:您应该运行以下命令,而不是运行“ java Test”: 需要1个内核时,“启动/ affinity 1 java测试”; 当需要2个核心时,“启动/ affinity 3 java测试”; .... 使用的参数应遵循以下格式:

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

您可以使用“ System.out.println(Runtime.getRuntime()。availableProcessors());进行检查。

答案 4 :(得分:0)

作为最后的手段,我可​​以将Java VM在任务管理器中的亲和力设置为仅使用1个(或更多)CPU。 (这当然仍然允许1个CPU上的多个线程,但如果没有其他任何更好的想法,它可能是我想要的最接近的东西)

答案 5 :(得分:0)

JVM的CPU限制问题已在Java 10中解决,并从内部版本8u191反向移植到Java 8:

        KeyStore sourceKeystore = KeyStore.getInstance("jks");
        try (InputStream stream = new BufferedInputStream(Files.newInputStream(sourceKeystorePath))) {
            sourceKeystore.load(stream, sourceKeystorePassword);
        }

        KeyStore destKeystore = KeyStore.getInstance("jks");
        destKeystore.load(null, destKeystorePassword);

        Enumeration<String> aliasList = sourceKeystore.aliases();
        while (aliasList.hasMoreElements()) {
            String alias = aliasList.nextElement();
            destKeystore.setCertificateEntry(alias, sourceKeystore.getCertificate(alias));
            if(sourceKeystore.isKeyEntry(alias)) {
                System.out.println(alias + " : is private key");
                Key key = sourceKeystore.getKey(alias, "secret".toCharArray());
                Certificate[] chain = new Certificate[1];
                chain[0] = sourceKeystore.getCertificate(alias);
                destKeystore.setKeyEntry(alias, key, "secret".toCharArray(), chain);
            }
        }

        try (OutputStream stream = new BufferedOutputStream(Files.newOutputStream(destKeystorePath))) {
            destKeystore.store(stream, destKeystorePassword);
        }

答案 6 :(得分:0)

为了测试这个,我使用了更高版本的java版本(java版本“14.0.2”2020-07-14)和这个选项:

-XX:ActiveProcessorCount=2

但是,这不会限制 JVM 使用超过 2 个处理器。如果有的话,它会使用更多。

根据我的理解(对 docs)和实验,这会影响线程池中线程数量的计算等。但是对数量施加任何限制分配给进程的 CPU 数量。

限制 cpu 使用的一种方法是在 docker 容器内运行 java 进程并使用

<块引用>

"--cpus"

泊坞窗选项。

这是我特别在 Mac OS 上使用的,目前没有支持的实用程序来限制 cpus。

另一种方法是使用特定于操作系统的实用程序,例如 taskset / isolcpus / cgroups(在 Linux 上可用)。

因此,如果问题是限制 java 进程使用的 CPU,那么 ActiveProcessorCount 选项本身就无用。在 docker 容器内运行它或使用操作系统特定的包装器来处理 CPU 或其他资源的分配/限制。