我想限制Java VM可用的线程/进程数,类似于设置可用内存的方式。我希望能够指定它只使用1个线程或任意数字。
注意:我无法在代码中设置它,因为我想限制的代码是一个我无法修改源代码的库。因此,它必须是强加于虚拟机级别的硬限制。 (或者,如果您可以对应用程序本身施加可以覆盖库的线程限制?)
注意2:这样做的目的是进行性能测试,以限制我想要测试的库,看看当它可以访问不同数量的CPU /线程时它的执行情况。
谢谢!
答案 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)
答案 3 :(得分:1)
尝试为Windows用户使用“亲和力”运行程序。
例如:您应该运行以下命令,而不是运行“ java Test”: 需要1个内核时,“启动/ affinity 1 java测试”; 当需要2个核心时,“启动/ affinity 3 java测试”; .... 使用的参数应遵循以下格式:
您可以使用“ 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 或其他资源的分配/限制。