mirror of
https://github.com/openjdk/jdk.git
synced 2026-02-06 00:18:34 +00:00
8338890: Add monitoring/management interface for the virtual thread scheduler
Reviewed-by: kevinw
This commit is contained in:
parent
5e822c24bb
commit
7e2bcf6d00
@ -65,6 +65,7 @@ import java.util.PropertyPermission;
|
||||
import java.util.ResourceBundle;
|
||||
import java.util.Set;
|
||||
import java.util.WeakHashMap;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.stream.Stream;
|
||||
@ -2766,6 +2767,10 @@ public final class System {
|
||||
}
|
||||
}
|
||||
|
||||
public Executor virtualThreadDefaultScheduler() {
|
||||
return VirtualThread.defaultScheduler();
|
||||
}
|
||||
|
||||
public StackWalker newStackWalkerInstance(Set<StackWalker.Option> options,
|
||||
ContinuationScope contScope,
|
||||
Continuation continuation) {
|
||||
|
||||
@ -142,6 +142,14 @@ final class VirtualThread extends BaseVirtualThread {
|
||||
// termination object when joining, created lazily if needed
|
||||
private volatile CountDownLatch termination;
|
||||
|
||||
|
||||
/**
|
||||
* Returns the default scheduler.
|
||||
*/
|
||||
static Executor defaultScheduler() {
|
||||
return DEFAULT_SCHEDULER;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the continuation scope used for virtual threads.
|
||||
*/
|
||||
|
||||
@ -44,6 +44,7 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.RejectedExecutionException;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
@ -601,6 +602,11 @@ public interface JavaLangAccess {
|
||||
*/
|
||||
void unparkVirtualThread(Thread thread);
|
||||
|
||||
/**
|
||||
* Returns the virtual thread default scheduler.
|
||||
*/
|
||||
Executor virtualThreadDefaultScheduler();
|
||||
|
||||
/**
|
||||
* Creates a new StackWalker
|
||||
*/
|
||||
|
||||
@ -172,6 +172,7 @@ module java.base {
|
||||
jdk.jartool,
|
||||
jdk.jlink,
|
||||
jdk.jfr,
|
||||
jdk.management,
|
||||
jdk.net,
|
||||
jdk.sctp,
|
||||
jdk.crypto.cryptoki;
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -41,6 +41,7 @@ import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
import javax.management.DynamicMBean;
|
||||
import jdk.management.VirtualThreadSchedulerMXBean;
|
||||
import sun.management.ManagementFactoryHelper;
|
||||
import sun.management.spi.PlatformMBeanProvider;
|
||||
|
||||
@ -163,6 +164,41 @@ public final class PlatformMBeanProviderImpl extends PlatformMBeanProvider {
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* VirtualThreadSchedulerMXBean.
|
||||
*/
|
||||
initMBeanList.add(new PlatformComponent<VirtualThreadSchedulerMXBean>() {
|
||||
private final Set<Class<? extends VirtualThreadSchedulerMXBean>> mbeanInterfaces =
|
||||
Set.of(VirtualThreadSchedulerMXBean.class);
|
||||
private final Set<String> mbeanInterfaceNames =
|
||||
Set.of(VirtualThreadSchedulerMXBean.class.getName());
|
||||
private VirtualThreadSchedulerMXBean impl;
|
||||
|
||||
@Override
|
||||
public Set<Class<? extends VirtualThreadSchedulerMXBean>> mbeanInterfaces() {
|
||||
return mbeanInterfaces;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> mbeanInterfaceNames() {
|
||||
return mbeanInterfaceNames;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getObjectNamePattern() {
|
||||
return "jdk.management:type=VirtualThreadScheduler";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, VirtualThreadSchedulerMXBean> nameToMBeanMap() {
|
||||
VirtualThreadSchedulerMXBean impl = this.impl;
|
||||
if (impl == null) {
|
||||
this.impl = impl = VirtualThreadSchedulerImpls.create();
|
||||
}
|
||||
return Map.of("jdk.management:type=VirtualThreadScheduler", impl);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* OperatingSystemMXBean
|
||||
*/
|
||||
|
||||
@ -0,0 +1,185 @@
|
||||
/*
|
||||
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package com.sun.management.internal;
|
||||
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.ForkJoinPool;
|
||||
import javax.management.ObjectName;
|
||||
import jdk.management.VirtualThreadSchedulerMXBean;
|
||||
import jdk.internal.access.JavaLangAccess;
|
||||
import jdk.internal.access.SharedSecrets;
|
||||
import jdk.internal.vm.ContinuationSupport;
|
||||
import sun.management.Util;
|
||||
|
||||
/**
|
||||
* Provides the implementation of the management interface for the JDK's default virtual
|
||||
* thread scheduler.
|
||||
*/
|
||||
public class VirtualThreadSchedulerImpls {
|
||||
private VirtualThreadSchedulerImpls() {
|
||||
}
|
||||
|
||||
public static VirtualThreadSchedulerMXBean create() {
|
||||
if (ContinuationSupport.isSupported()) {
|
||||
return new VirtualThreadSchedulerImpl();
|
||||
} else {
|
||||
return new BoundVirtualThreadSchedulerImpl();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Base implementation of VirtualThreadSchedulerMXBean.
|
||||
*/
|
||||
private abstract static class BaseVirtualThreadSchedulerImpl
|
||||
implements VirtualThreadSchedulerMXBean {
|
||||
|
||||
abstract void implSetParallelism(int size);
|
||||
|
||||
@Override
|
||||
public final void setParallelism(int size) {
|
||||
Util.checkControlAccess();
|
||||
implSetParallelism(size);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final ObjectName getObjectName() {
|
||||
return Util.newObjectName("jdk.management:type=VirtualThreadScheduler");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
var sb = new StringBuilder("[parallelism=");
|
||||
sb.append(getParallelism());
|
||||
append(sb, "size", getPoolSize());
|
||||
append(sb, "mounted", getMountedVirtualThreadCount());
|
||||
append(sb, "queued", getQueuedVirtualThreadCount());
|
||||
sb.append(']');
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private void append(StringBuilder sb, String name, long value) {
|
||||
sb.append(", ").append(name).append('=');
|
||||
if (value >= 0) {
|
||||
sb.append(value);
|
||||
} else {
|
||||
sb.append("<unavailable>");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of VirtualThreadSchedulerMXBean when virtual threads are
|
||||
* implemented with continuations + scheduler.
|
||||
*/
|
||||
private static final class VirtualThreadSchedulerImpl extends BaseVirtualThreadSchedulerImpl {
|
||||
/**
|
||||
* Holder class for scheduler.
|
||||
*/
|
||||
private static class Scheduler {
|
||||
private static final Executor scheduler =
|
||||
SharedSecrets.getJavaLangAccess().virtualThreadDefaultScheduler();
|
||||
static Executor instance() {
|
||||
return scheduler;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getParallelism() {
|
||||
if (Scheduler.instance() instanceof ForkJoinPool pool) {
|
||||
return pool.getParallelism();
|
||||
}
|
||||
throw new InternalError(); // should not get here
|
||||
}
|
||||
|
||||
@Override
|
||||
void implSetParallelism(int size) {
|
||||
if (Scheduler.instance() instanceof ForkJoinPool pool) {
|
||||
pool.setParallelism(size);
|
||||
if (pool.getPoolSize() < size) {
|
||||
// FJ worker thread creation is on-demand
|
||||
Thread.startVirtualThread(() -> { });
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
throw new UnsupportedOperationException(); // should not get here
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPoolSize() {
|
||||
if (Scheduler.instance() instanceof ForkJoinPool pool) {
|
||||
return pool.getPoolSize();
|
||||
}
|
||||
return -1; // should not get here
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMountedVirtualThreadCount() {
|
||||
if (Scheduler.instance() instanceof ForkJoinPool pool) {
|
||||
return pool.getActiveThreadCount();
|
||||
}
|
||||
return -1; // should not get here
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getQueuedVirtualThreadCount() {
|
||||
if (Scheduler.instance() instanceof ForkJoinPool pool) {
|
||||
return pool.getQueuedTaskCount() + pool.getQueuedSubmissionCount();
|
||||
}
|
||||
return -1L; // should not get here
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of VirtualThreadSchedulerMXBean when virtual threads are backed
|
||||
* by platform threads.
|
||||
*/
|
||||
private static final class BoundVirtualThreadSchedulerImpl extends BaseVirtualThreadSchedulerImpl {
|
||||
@Override
|
||||
public int getParallelism() {
|
||||
return Integer.MAX_VALUE;
|
||||
}
|
||||
|
||||
@Override
|
||||
void implSetParallelism(int size) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPoolSize() {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMountedVirtualThreadCount() {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getQueuedVirtualThreadCount() {
|
||||
return -1L;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2004, 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2004, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -24,9 +24,8 @@
|
||||
*/
|
||||
|
||||
/**
|
||||
* This package contains the JDK's extension to
|
||||
* the standard implementation of the
|
||||
* {@link java.lang.management} API and also defines the management
|
||||
* This package contains JDK extensions to the standard implementation of
|
||||
* the {@link java.lang.management} API and also defines the management
|
||||
* interface for some other components of the platform.
|
||||
*
|
||||
* <p>
|
||||
|
||||
@ -0,0 +1,117 @@
|
||||
/*
|
||||
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package jdk.management;
|
||||
|
||||
import java.lang.management.ManagementFactory;
|
||||
import java.lang.management.PlatformManagedObject;
|
||||
import java.util.concurrent.ForkJoinPool;
|
||||
import javax.management.MBeanServer;
|
||||
import javax.management.ObjectName;
|
||||
|
||||
/**
|
||||
* Management interface for the JDK's {@linkplain Thread##virtual-threads virtual thread}
|
||||
* scheduler.
|
||||
*
|
||||
* <p> {@code VirtualThreadSchedulerMXBean} supports monitoring of the virtual thread
|
||||
* scheduler's target parallelism, the {@linkplain Thread##platform-threads platform threads}
|
||||
* used by the scheduler, and the number of virtual threads queued to the scheduler. It
|
||||
* also supports dynamically changing the scheduler's target parallelism.
|
||||
*
|
||||
* <p> The management interface is registered with the platform {@link MBeanServer
|
||||
* MBeanServer}. The {@link ObjectName ObjectName} that uniquely identifies the management
|
||||
* interface within the {@code MBeanServer} is: "jdk.management:type=VirtualThreadScheduler".
|
||||
*
|
||||
* <p> Direct access to the MXBean interface can be obtained with
|
||||
* {@link ManagementFactory#getPlatformMXBean(Class)}.
|
||||
*
|
||||
* @since 24
|
||||
*/
|
||||
public interface VirtualThreadSchedulerMXBean extends PlatformManagedObject {
|
||||
|
||||
/**
|
||||
* {@return the scheduler's target parallelism}
|
||||
*
|
||||
* @see ForkJoinPool#getParallelism()
|
||||
*/
|
||||
int getParallelism();
|
||||
|
||||
/**
|
||||
* Sets the scheduler's target parallelism.
|
||||
*
|
||||
* <p> Increasing the target parallelism allows the scheduler to use more platform
|
||||
* threads to <i>carry</i> virtual threads if required. Decreasing the target parallelism
|
||||
* reduces the number of threads that the scheduler may use to carry virtual threads.
|
||||
*
|
||||
* @apiNote If virtual threads are mounting and unmounting frequently then downward
|
||||
* adjustment of the target parallelism will likely come into effect quickly.
|
||||
*
|
||||
* @implNote The JDK's virtual thread scheduler is a {@link ForkJoinPool}. Target
|
||||
* parallelism defaults to the number of {@linkplain Runtime#availableProcessors()
|
||||
* available processors}. The minimum target parallelism is 1, the maximum target
|
||||
* parallelism is 32767.
|
||||
*
|
||||
* @param size the target parallelism level
|
||||
* @throws IllegalArgumentException if size is less than the minimum, or
|
||||
* greater than the maximum, supported by the scheduler
|
||||
* @throws UnsupportedOperationException if changing the target
|
||||
* parallelism is not suppored by the scheduler
|
||||
*
|
||||
* @see ForkJoinPool#setParallelism(int)
|
||||
*/
|
||||
void setParallelism(int size);
|
||||
|
||||
/**
|
||||
* {@return the current number of platform threads that the scheduler has started
|
||||
* but have not terminated; {@code -1} if not known}
|
||||
*
|
||||
* <p> The count includes the platform threads that are currently <i>carrying</i>
|
||||
* virtual threads and the platform threads that are not currently carrying virtual
|
||||
* threads. The thread count may be greater than the scheduler's target parallelism.
|
||||
*
|
||||
* @implNote The JDK's virtual thread scheduler is a {@link ForkJoinPool}. The pool
|
||||
* size is the {@linkplain ForkJoinPool#getPoolSize() number of worker threads}.
|
||||
*/
|
||||
int getPoolSize();
|
||||
|
||||
/**
|
||||
* {@return an estimate of the number of virtual threads that are currently
|
||||
* <i>mounted</i> by the scheduler; {@code -1} if not known}
|
||||
*
|
||||
* <p> The number of mounted virtual threads is equal to the number of platform
|
||||
* threads carrying virtual threads.
|
||||
*
|
||||
* @implNote This method may overestimate the number of virtual threads that are mounted.
|
||||
*/
|
||||
int getMountedVirtualThreadCount();
|
||||
|
||||
/**
|
||||
* {@return an estimate of the number of virtual threads that are queued to
|
||||
* the scheduler to start or continue execution; {@code -1} if not known}
|
||||
*
|
||||
* @implNote This method may overestimate the number of virtual threads that are
|
||||
* queued to execute.
|
||||
*/
|
||||
long getQueuedVirtualThreadCount();
|
||||
}
|
||||
@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/**
|
||||
* This package contains JDK extensions to the standard implementation of the
|
||||
* {@link java.lang.management} API.
|
||||
*
|
||||
* @since 24
|
||||
*/
|
||||
|
||||
package jdk.management;
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -23,9 +23,18 @@
|
||||
* questions.
|
||||
*/
|
||||
|
||||
import java.lang.management.ManagementFactory;
|
||||
|
||||
/**
|
||||
* Defines JDK-specific management interfaces for the JVM.
|
||||
*
|
||||
* <p> This module contains the JDK's extensions to the standard implementation
|
||||
* of the {@link java.lang.management} API and also defines the management
|
||||
* interfaces for some other components of the platform.
|
||||
*
|
||||
* <p> All platform MBeans are registered in the <em>platform MBeanServer</em>
|
||||
* which can be obtained with {@link ManagementFactory#getPlatformMBeanServer}.
|
||||
*
|
||||
* @moduleGraph
|
||||
* @since 9
|
||||
*/
|
||||
@ -33,6 +42,7 @@ module jdk.management {
|
||||
requires transitive java.management;
|
||||
|
||||
exports com.sun.management;
|
||||
exports jdk.management;
|
||||
|
||||
provides sun.management.spi.PlatformMBeanProvider with
|
||||
com.sun.management.internal.PlatformMBeanProviderImpl;
|
||||
|
||||
@ -25,7 +25,7 @@
|
||||
* @test id=default
|
||||
* @bug 8312498
|
||||
* @summary Basic test for JVMTI GetThreadState with virtual threads
|
||||
* @modules java.base/java.lang:+open
|
||||
* @modules jdk.management
|
||||
* @library /test/lib
|
||||
* @run junit/othervm/native --enable-native-access=ALL-UNNAMED GetThreadStateTest
|
||||
*/
|
||||
@ -33,7 +33,7 @@
|
||||
/*
|
||||
* @test id=no-vmcontinuations
|
||||
* @requires vm.continuations
|
||||
* @modules java.base/java.lang:+open
|
||||
* @modules jdk.management
|
||||
* @library /test/lib
|
||||
* @run junit/othervm/native -XX:+UnlockExperimentalVMOptions -XX:-VMContinuations --enable-native-access=ALL-UNNAMED GetThreadStateTest
|
||||
*/
|
||||
@ -42,7 +42,7 @@ import java.util.StringJoiner;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.locks.LockSupport;
|
||||
|
||||
import jdk.test.lib.thread.VThreadRunner;
|
||||
import jdk.test.lib.thread.VThreadRunner; // ensureParallelism requires jdk.management
|
||||
import jdk.test.lib.thread.VThreadPinner;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
@ -28,7 +28,7 @@
|
||||
* @requires vm.continuations
|
||||
* @requires vm.jvmti
|
||||
* @requires vm.compMode != "Xcomp"
|
||||
* @modules java.base/java.lang:+open
|
||||
* @modules jdk.management
|
||||
* @library /test/lib
|
||||
* @run main/othervm/native
|
||||
* -Djdk.attach.allowAttachSelf=true -XX:+EnableDynamicAgentLoading VThreadEventTest attach
|
||||
|
||||
@ -262,6 +262,7 @@ jdk_text = \
|
||||
|
||||
jdk_management = \
|
||||
java/lang/management \
|
||||
jdk/management \
|
||||
com/sun/management \
|
||||
sun/management \
|
||||
jdk/internal/agent
|
||||
@ -287,6 +288,7 @@ jdk_launcher = \
|
||||
jdk_loom = \
|
||||
com/sun/management/HotSpotDiagnosticMXBean \
|
||||
com/sun/management/ThreadMXBean \
|
||||
jdk/management/VirtualThreadSchedulerMXBean \
|
||||
java/lang/Thread \
|
||||
java/lang/ThreadGroup \
|
||||
java/lang/management/ThreadMXBean \
|
||||
|
||||
@ -25,7 +25,7 @@
|
||||
* @test
|
||||
* @summary Basic test for JFR jdk.VirtualThreadXXX events
|
||||
* @requires vm.continuations
|
||||
* @modules jdk.jfr java.base/java.lang:+open
|
||||
* @modules jdk.jfr java.base/java.lang:+open jdk.management
|
||||
* @library /test/lib
|
||||
* @run junit/othervm --enable-native-access=ALL-UNNAMED JfrEvents
|
||||
*/
|
||||
@ -50,7 +50,7 @@ import jdk.jfr.consumer.RecordedEvent;
|
||||
import jdk.jfr.consumer.RecordingFile;
|
||||
|
||||
import jdk.test.lib.thread.VThreadPinner;
|
||||
import jdk.test.lib.thread.VThreadRunner;
|
||||
import jdk.test.lib.thread.VThreadRunner; // ensureParallelism requires jdk.management
|
||||
import jdk.test.lib.thread.VThreadScheduler;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
|
||||
@ -24,7 +24,7 @@
|
||||
/*
|
||||
* @test id=default
|
||||
* @summary Test virtual thread with monitor enter/exit
|
||||
* @modules java.base/java.lang:+open
|
||||
* @modules java.base/java.lang:+open jdk.management
|
||||
* @library /test/lib
|
||||
* @run junit/othervm --enable-native-access=ALL-UNNAMED MonitorEnterExit
|
||||
*/
|
||||
@ -43,7 +43,7 @@ import java.util.stream.IntStream;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import jdk.test.lib.thread.VThreadPinner;
|
||||
import jdk.test.lib.thread.VThreadRunner;
|
||||
import jdk.test.lib.thread.VThreadRunner; // ensureParallelism requires jdk.management
|
||||
import jdk.test.lib.thread.VThreadScheduler;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
|
||||
@ -24,7 +24,7 @@
|
||||
/*
|
||||
* @test id=default
|
||||
* @summary Test virtual threads using Object.wait/notifyAll
|
||||
* @modules java.base/java.lang:+open
|
||||
* @modules java.base/java.lang:+open jdk.management
|
||||
* @library /test/lib
|
||||
* @run junit/othervm --enable-native-access=ALL-UNNAMED MonitorWaitNotify
|
||||
*/
|
||||
@ -46,8 +46,7 @@ import java.util.stream.Stream;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import jdk.test.lib.thread.VThreadScheduler;
|
||||
import jdk.test.lib.thread.VThreadRunner;
|
||||
import jdk.test.lib.thread.VThreadRunner;
|
||||
import jdk.test.lib.thread.VThreadRunner; // ensureParallelism requires jdk.management
|
||||
import jdk.test.lib.thread.VThreadPinner;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
|
||||
@ -25,7 +25,7 @@
|
||||
* @test id=default
|
||||
* @bug 8284161 8286788 8321270
|
||||
* @summary Test Thread API with virtual threads
|
||||
* @modules java.base/java.lang:+open
|
||||
* @modules java.base/java.lang:+open jdk.management
|
||||
* @library /test/lib
|
||||
* @run junit/othervm --enable-native-access=ALL-UNNAMED ThreadAPI
|
||||
*/
|
||||
@ -33,7 +33,7 @@
|
||||
/*
|
||||
* @test id=no-vmcontinuations
|
||||
* @requires vm.continuations
|
||||
* @modules java.base/java.lang:+open
|
||||
* @modules java.base/java.lang:+open jdk.management
|
||||
* @library /test/lib
|
||||
* @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:-VMContinuations
|
||||
* --enable-native-access=ALL-UNNAMED ThreadAPI
|
||||
@ -62,7 +62,7 @@ import java.util.stream.Stream;
|
||||
import java.nio.channels.Selector;
|
||||
|
||||
import jdk.test.lib.thread.VThreadPinner;
|
||||
import jdk.test.lib.thread.VThreadRunner;
|
||||
import jdk.test.lib.thread.VThreadRunner; // ensureParallelism requires jdk.management
|
||||
import jdk.test.lib.thread.VThreadScheduler;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
|
||||
@ -24,7 +24,7 @@
|
||||
/**
|
||||
* @test
|
||||
* @summary Test parking when pinned and emitting the JFR VirtualThreadPinnedEvent throws
|
||||
* @modules java.base/java.lang:+open java.base/jdk.internal.event
|
||||
* @modules java.base/java.lang:+open java.base/jdk.internal.event jdk.management
|
||||
* @library /test/lib
|
||||
* @compile/module=java.base jdk/internal/event/VirtualThreadPinnedEvent.java
|
||||
* @run junit/othervm --enable-native-access=ALL-UNNAMED VirtualThreadPinnedEventThrows
|
||||
@ -36,7 +36,7 @@ import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.concurrent.locks.LockSupport;
|
||||
import jdk.internal.event.VirtualThreadPinnedEvent;
|
||||
|
||||
import jdk.test.lib.thread.VThreadRunner;
|
||||
import jdk.test.lib.thread.VThreadRunner; // ensureParallelism requires jdk.management
|
||||
import jdk.test.lib.thread.VThreadPinner;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
|
||||
@ -26,7 +26,7 @@
|
||||
* @summary Stress test Thread.getStackTrace on virtual threads that are blocking or
|
||||
* blocked on monitorenter
|
||||
* @requires vm.debug != true
|
||||
* @modules java.base/java.lang:+open
|
||||
* @modules jdk.management
|
||||
* @library /test/lib
|
||||
* @run main/othervm GetStackTraceALotWhenBlocking 500000
|
||||
*/
|
||||
@ -34,7 +34,7 @@
|
||||
/*
|
||||
* @test
|
||||
* @requires vm.debug == true & vm.continuations
|
||||
* @modules java.base/java.lang:+open
|
||||
* @modules jdk.management
|
||||
* @library /test/lib
|
||||
* @run main/othervm/timeout=300 GetStackTraceALotWhenBlocking 50000
|
||||
*/
|
||||
@ -42,7 +42,7 @@
|
||||
import java.time.Instant;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import jdk.test.lib.thread.VThreadRunner;
|
||||
import jdk.test.lib.thread.VThreadRunner; // ensureParallelism requires jdk.management
|
||||
|
||||
public class GetStackTraceALotWhenBlocking {
|
||||
|
||||
|
||||
@ -26,7 +26,7 @@
|
||||
* @bug 8322818
|
||||
* @summary Stress test Thread.getStackTrace on a virtual thread that is pinned
|
||||
* @requires vm.debug != true
|
||||
* @modules java.base/java.lang:+open
|
||||
* @modules jdk.management
|
||||
* @library /test/lib
|
||||
* @run main/othervm --enable-native-access=ALL-UNNAMED GetStackTraceALotWhenPinned 500000
|
||||
*/
|
||||
@ -34,7 +34,7 @@
|
||||
/*
|
||||
* @test
|
||||
* @requires vm.debug == true
|
||||
* @modules java.base/java.lang:+open
|
||||
* @modules jdk.management
|
||||
* @library /test/lib
|
||||
* @run main/othervm/timeout=300 --enable-native-access=ALL-UNNAMED GetStackTraceALotWhenPinned 200000
|
||||
*/
|
||||
@ -42,7 +42,7 @@
|
||||
import java.time.Instant;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.locks.LockSupport;
|
||||
import jdk.test.lib.thread.VThreadRunner;
|
||||
import jdk.test.lib.thread.VThreadRunner; // ensureParallelism requires jdk.management
|
||||
import jdk.test.lib.thread.VThreadPinner;
|
||||
|
||||
public class GetStackTraceALotWhenPinned {
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -26,7 +26,7 @@
|
||||
* @bug 8284161 8287103
|
||||
* @summary Test ThredMXBean.findMonitorDeadlockedThreads with cycles of
|
||||
* platform and virtual threads in deadlock
|
||||
* @modules java.base/java.lang:+open java.management
|
||||
* @modules java.management jdk.management
|
||||
* @library /test/lib
|
||||
* @run main/othervm VirtualThreadDeadlocks PP
|
||||
* @run main/othervm VirtualThreadDeadlocks PV
|
||||
@ -36,7 +36,7 @@
|
||||
/**
|
||||
* @test id=no-vmcontinuations
|
||||
* @requires vm.continuations
|
||||
* @modules java.base/java.lang:+open java.management
|
||||
* @modules java.management jdk.management
|
||||
* @library /test/lib
|
||||
* @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:-VMContinuations VirtualThreadDeadlocks PP
|
||||
* @run main/othervm -XX:+UnlockExperimentalVMOptions -XX:-VMContinuations VirtualThreadDeadlocks PV
|
||||
@ -48,7 +48,7 @@ import java.lang.management.ThreadMXBean;
|
||||
import java.util.Arrays;
|
||||
import java.util.concurrent.CyclicBarrier;
|
||||
import java.util.stream.Stream;
|
||||
import jdk.test.lib.thread.VThreadRunner;
|
||||
import jdk.test.lib.thread.VThreadRunner; // ensureParallelism requires jdk.management
|
||||
|
||||
public class VirtualThreadDeadlocks {
|
||||
private static final Object LOCK1 = new Object();
|
||||
|
||||
@ -0,0 +1,260 @@
|
||||
/*
|
||||
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8338890
|
||||
* @summary Basic test for jdk.management.VirtualThreadSchedulerMXBean
|
||||
* @requires vm.continuations
|
||||
* @modules jdk.management
|
||||
* @library /test/lib
|
||||
* @run junit/othervm VirtualThreadSchedulerMXBeanTest
|
||||
*/
|
||||
|
||||
import java.lang.management.ManagementFactory;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.stream.IntStream;
|
||||
import javax.management.MBeanServer;
|
||||
import jdk.management.VirtualThreadSchedulerMXBean;
|
||||
|
||||
import jdk.test.lib.thread.VThreadRunner;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import static org.junit.jupiter.api.Assumptions.*;
|
||||
|
||||
class VirtualThreadSchedulerMXBeanTest {
|
||||
|
||||
/**
|
||||
* VirtualThreadSchedulerMXBean objects to test.
|
||||
*/
|
||||
private static Stream<VirtualThreadSchedulerMXBean> managedBeans() throws Exception {
|
||||
var bean1 = ManagementFactory.getPlatformMXBean(VirtualThreadSchedulerMXBean.class);
|
||||
|
||||
MBeanServer server = ManagementFactory.getPlatformMBeanServer();
|
||||
var bean2 = ManagementFactory.newPlatformMXBeanProxy(server,
|
||||
"jdk.management:type=VirtualThreadScheduler",
|
||||
VirtualThreadSchedulerMXBean.class);
|
||||
|
||||
return Stream.of(bean1, bean2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test default parallelism.
|
||||
*/
|
||||
@ParameterizedTest
|
||||
@MethodSource("managedBeans")
|
||||
void testDefaultParallelism(VirtualThreadSchedulerMXBean bean) {
|
||||
assertEquals(Runtime.getRuntime().availableProcessors(), bean.getParallelism());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test increasing parallelism.
|
||||
*/
|
||||
@ParameterizedTest
|
||||
@MethodSource("managedBeans")
|
||||
void testIncreaseParallelism(VirtualThreadSchedulerMXBean bean) throws Exception {
|
||||
assumeFalse(Thread.currentThread().isVirtual(), "Main thread is a virtual thread");
|
||||
|
||||
final int parallelism = bean.getParallelism();
|
||||
try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
|
||||
var done = new AtomicBoolean();
|
||||
Runnable busyTask = () -> {
|
||||
while (!done.get()) {
|
||||
Thread.onSpinWait();
|
||||
}
|
||||
};
|
||||
|
||||
try {
|
||||
// saturate
|
||||
IntStream.range(0, parallelism).forEach(_ -> executor.submit(busyTask));
|
||||
awaitPoolSizeGte(bean, parallelism);
|
||||
awaitMountedVirtualThreadCountGte(bean, parallelism);
|
||||
|
||||
// increase parallelism
|
||||
for (int k = 1; k <= 4; k++) {
|
||||
int newParallelism = parallelism + k;
|
||||
bean.setParallelism(newParallelism);
|
||||
executor.submit(busyTask);
|
||||
|
||||
// pool size and mounted virtual thread should increase
|
||||
awaitPoolSizeGte(bean, newParallelism);
|
||||
awaitMountedVirtualThreadCountGte(bean, newParallelism);
|
||||
}
|
||||
} finally {
|
||||
done.set(true);
|
||||
}
|
||||
} finally {
|
||||
bean.setParallelism(parallelism); // restore
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test reducing parallelism.
|
||||
*/
|
||||
@ParameterizedTest
|
||||
@MethodSource("managedBeans")
|
||||
void testReduceParallelism(VirtualThreadSchedulerMXBean bean) throws Exception {
|
||||
assumeFalse(Thread.currentThread().isVirtual(), "Main thread is a virtual thread");
|
||||
|
||||
final int parallelism = bean.getParallelism();
|
||||
try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
|
||||
var done = new AtomicBoolean();
|
||||
var sleep = new AtomicBoolean();
|
||||
|
||||
// spin when !sleep
|
||||
Runnable busyTask = () -> {
|
||||
while (!done.get()) {
|
||||
if (sleep.get()) {
|
||||
try {
|
||||
Thread.sleep(10);
|
||||
} catch (InterruptedException e) { }
|
||||
} else {
|
||||
Thread.onSpinWait();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
try {
|
||||
// increase parallelism + saturate
|
||||
int newParallelism = parallelism + 4;
|
||||
bean.setParallelism(newParallelism);
|
||||
IntStream.range(0, newParallelism).forEach(_ -> executor.submit(busyTask));
|
||||
awaitMountedVirtualThreadCountGte(bean, newParallelism);
|
||||
|
||||
// reduce parallelism and workload
|
||||
newParallelism = Math.clamp(parallelism / 2, 1, parallelism);
|
||||
bean.setParallelism(newParallelism);
|
||||
sleep.set(true);
|
||||
// mounted virtual thread count should reduce
|
||||
awaitMountedVirtualThreadCountLte(bean, newParallelism);
|
||||
|
||||
// increase workload, the mounted virtual thread count should not increase
|
||||
sleep.set(false);
|
||||
for (int i = 0; i < 5; i++) {
|
||||
Thread.sleep(100);
|
||||
assertTrue(bean.getMountedVirtualThreadCount() <= newParallelism);
|
||||
}
|
||||
|
||||
} finally {
|
||||
done.set(true);
|
||||
}
|
||||
} finally {
|
||||
bean.setParallelism(parallelism); // restore
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test getPoolSize.
|
||||
*/
|
||||
@ParameterizedTest
|
||||
@MethodSource("managedBeans")
|
||||
void testPoolSize(VirtualThreadSchedulerMXBean bean) {
|
||||
assertTrue(bean.getPoolSize() >= 0);
|
||||
VThreadRunner.run(() -> {
|
||||
assertTrue(Thread.currentThread().isVirtual());
|
||||
assertTrue(bean.getPoolSize() >= 1);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Test getMountedVirtualThreadCount.
|
||||
*/
|
||||
@ParameterizedTest
|
||||
@MethodSource("managedBeans")
|
||||
void testMountedVirtualThreadCount(VirtualThreadSchedulerMXBean bean) {
|
||||
assertTrue(bean.getMountedVirtualThreadCount() >= 0);
|
||||
VThreadRunner.run(() -> {
|
||||
assertTrue(Thread.currentThread().isVirtual());
|
||||
assertTrue(bean.getMountedVirtualThreadCount() >= 1);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Test getQueuedVirtualThreadCount.
|
||||
*/
|
||||
@ParameterizedTest
|
||||
@MethodSource("managedBeans")
|
||||
void testQueuedVirtualThreadCount(VirtualThreadSchedulerMXBean bean) throws Exception {
|
||||
assumeFalse(Thread.currentThread().isVirtual(), "Main thread is a virtual thread");
|
||||
|
||||
try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
|
||||
var done = new AtomicBoolean();
|
||||
Runnable busyTask = () -> {
|
||||
while (!done.get()) {
|
||||
Thread.onSpinWait();
|
||||
}
|
||||
};
|
||||
|
||||
try {
|
||||
// saturate
|
||||
int parallelism = bean.getParallelism();
|
||||
IntStream.range(0, parallelism).forEach(_ -> executor.submit(busyTask));
|
||||
awaitMountedVirtualThreadCountGte(bean, parallelism);
|
||||
|
||||
// start 5 virtual threads, their tasks will be queued to execute
|
||||
for (int i = 0; i < 5; i++) {
|
||||
executor.submit(() -> { });
|
||||
}
|
||||
assertTrue(bean.getQueuedVirtualThreadCount() >= 5);
|
||||
} finally {
|
||||
done.set(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Waits for pool size >= target to be true.
|
||||
*/
|
||||
void awaitPoolSizeGte(VirtualThreadSchedulerMXBean bean, int target) throws InterruptedException {
|
||||
System.err.format("await pool size >= %d ...%n", target);
|
||||
while (bean.getPoolSize() < target) {
|
||||
Thread.sleep(10);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Waits for the mounted virtual thread count >= target to be true.
|
||||
*/
|
||||
void awaitMountedVirtualThreadCountGte(VirtualThreadSchedulerMXBean bean,
|
||||
int target) throws InterruptedException {
|
||||
System.err.format("await mounted virtual thread count >= %d ...%n", target);
|
||||
while (bean.getMountedVirtualThreadCount() < target) {
|
||||
Thread.sleep(10);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Waits for the mounted virtual thread count <= target to be true.
|
||||
*/
|
||||
void awaitMountedVirtualThreadCountLte(VirtualThreadSchedulerMXBean bean,
|
||||
int target) throws InterruptedException {
|
||||
System.err.format("await mounted virtual thread count <= %d ...%n", target);
|
||||
while (bean.getMountedVirtualThreadCount() > target) {
|
||||
Thread.sleep(10);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -23,10 +23,10 @@
|
||||
|
||||
package jdk.test.lib.thread;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.management.ManagementFactory;
|
||||
import java.time.Duration;
|
||||
import java.util.concurrent.ForkJoinPool;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import jdk.management.VirtualThreadSchedulerMXBean;
|
||||
|
||||
/**
|
||||
* Helper class to support tests running tasks in a virtual thread.
|
||||
@ -133,39 +133,36 @@ public class VThreadRunner {
|
||||
run(null, 0, task);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the virtual thread scheduler.
|
||||
*/
|
||||
private static ForkJoinPool defaultScheduler() {
|
||||
try {
|
||||
var clazz = Class.forName("java.lang.VirtualThread");
|
||||
var field = clazz.getDeclaredField("DEFAULT_SCHEDULER");
|
||||
field.setAccessible(true);
|
||||
return (ForkJoinPool) field.get(null);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the virtual thread scheduler's target parallelism.
|
||||
*
|
||||
* <p> Tests using this method should use "{@code @modules jdk.management}" to help
|
||||
* test selection.
|
||||
*
|
||||
* @return the previous parallelism level
|
||||
*/
|
||||
public static int setParallelism(int size) {
|
||||
return defaultScheduler().setParallelism(size);
|
||||
var bean = ManagementFactory.getPlatformMXBean(VirtualThreadSchedulerMXBean.class);
|
||||
int parallelism = bean.getParallelism();
|
||||
bean.setParallelism(size);
|
||||
return parallelism;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures that the virtual thread scheduler's target parallelism is at least
|
||||
* the given size. If the target parallelism is less than the given size then
|
||||
* it is changed to the given size.
|
||||
*
|
||||
* <p> Tests using this method should use "{@code @modules jdk.management}" to help
|
||||
* test selection.
|
||||
*
|
||||
* @return the previous parallelism level
|
||||
*/
|
||||
public static int ensureParallelism(int size) {
|
||||
ForkJoinPool pool = defaultScheduler();
|
||||
int parallelism = pool.getParallelism();
|
||||
var bean = ManagementFactory.getPlatformMXBean(VirtualThreadSchedulerMXBean.class);
|
||||
int parallelism = bean.getParallelism();
|
||||
if (size > parallelism) {
|
||||
pool.setParallelism(size);
|
||||
bean.setParallelism(size);
|
||||
}
|
||||
return parallelism;
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user