< prev index next >

src/java.base/share/classes/java/lang/VirtualThread.java

Print this page

   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 package java.lang;
  26 

  27 import java.util.Arrays;
  28 import java.util.Locale;
  29 import java.util.Objects;
  30 import java.util.concurrent.CountDownLatch;
  31 import java.util.concurrent.Executor;
  32 import java.util.concurrent.Executors;
  33 import java.util.concurrent.ForkJoinPool;
  34 import java.util.concurrent.ForkJoinPool.ForkJoinWorkerThreadFactory;
  35 import java.util.concurrent.ForkJoinTask;
  36 import java.util.concurrent.Future;
  37 import java.util.concurrent.RejectedExecutionException;
  38 import java.util.concurrent.ScheduledExecutorService;
  39 import java.util.concurrent.ScheduledThreadPoolExecutor;
  40 import java.util.concurrent.TimeUnit;
  41 import java.util.stream.Stream;
  42 import jdk.internal.event.VirtualThreadEndEvent;
  43 import jdk.internal.event.VirtualThreadStartEvent;
  44 import jdk.internal.event.VirtualThreadSubmitFailedEvent;
  45 import jdk.internal.misc.CarrierThread;
  46 import jdk.internal.misc.InnocuousThread;

  48 import jdk.internal.vm.Continuation;
  49 import jdk.internal.vm.ContinuationScope;
  50 import jdk.internal.vm.StackableScope;
  51 import jdk.internal.vm.ThreadContainer;
  52 import jdk.internal.vm.ThreadContainers;
  53 import jdk.internal.vm.annotation.ChangesCurrentThread;
  54 import jdk.internal.vm.annotation.Hidden;
  55 import jdk.internal.vm.annotation.IntrinsicCandidate;
  56 import jdk.internal.vm.annotation.JvmtiHideEvents;
  57 import jdk.internal.vm.annotation.JvmtiMountTransition;
  58 import jdk.internal.vm.annotation.ReservedStackAccess;
  59 import sun.nio.ch.Interruptible;
  60 import static java.util.concurrent.TimeUnit.*;
  61 
  62 /**
  63  * A thread that is scheduled by the Java virtual machine rather than the operating system.
  64  */
  65 final class VirtualThread extends BaseVirtualThread {
  66     private static final Unsafe U = Unsafe.getUnsafe();
  67     private static final ContinuationScope VTHREAD_SCOPE = new ContinuationScope("VirtualThreads");
  68     private static final ForkJoinPool DEFAULT_SCHEDULER = createDefaultScheduler();
  69     private static final ScheduledExecutorService[] DELAYED_TASK_SCHEDULERS = createDelayedTaskSchedulers();
  70 
  71     private static final long STATE = U.objectFieldOffset(VirtualThread.class, "state");
  72     private static final long PARK_PERMIT = U.objectFieldOffset(VirtualThread.class, "parkPermit");
  73     private static final long CARRIER_THREAD = U.objectFieldOffset(VirtualThread.class, "carrierThread");
  74     private static final long TERMINATION = U.objectFieldOffset(VirtualThread.class, "termination");
  75     private static final long ON_WAITING_LIST = U.objectFieldOffset(VirtualThread.class, "onWaitingList");
  76 
  77     // scheduler and continuation
  78     private final Executor scheduler;
  79     private final Continuation cont;
  80     private final Runnable runContinuation;
  81 
  82     // virtual thread state, accessed by VM
  83     private volatile int state;
  84 
  85     /*
  86      * Virtual thread state transitions:
  87      *
  88      *      NEW -> STARTED         // Thread.start, schedule to run

1393 
1394     @IntrinsicCandidate
1395     @JvmtiMountTransition
1396     private native void notifyJvmtiMount(boolean hide);
1397 
1398     @IntrinsicCandidate
1399     @JvmtiMountTransition
1400     private native void notifyJvmtiUnmount(boolean hide);
1401 
1402     @IntrinsicCandidate
1403     private static native void notifyJvmtiDisableSuspend(boolean enter);
1404 
1405     private static native void registerNatives();
1406     static {
1407         registerNatives();
1408 
1409         // ensure VTHREAD_GROUP is created, may be accessed by JVMTI
1410         var group = Thread.virtualThreadGroup();
1411     }
1412 




























1413     /**
1414      * Creates the default ForkJoinPool scheduler.
1415      */
1416     private static ForkJoinPool createDefaultScheduler() {
1417         ForkJoinWorkerThreadFactory factory = pool -> new CarrierThread(pool);
1418         int parallelism, maxPoolSize, minRunnable;
1419         String parallelismValue = System.getProperty("jdk.virtualThreadScheduler.parallelism");
1420         String maxPoolSizeValue = System.getProperty("jdk.virtualThreadScheduler.maxPoolSize");
1421         String minRunnableValue = System.getProperty("jdk.virtualThreadScheduler.minRunnable");
1422         if (parallelismValue != null) {
1423             parallelism = Integer.parseInt(parallelismValue);
1424         } else {
1425             parallelism = Runtime.getRuntime().availableProcessors();
1426         }
1427         if (maxPoolSizeValue != null) {
1428             maxPoolSize = Integer.parseInt(maxPoolSizeValue);
1429             parallelism = Integer.min(parallelism, maxPoolSize);
1430         } else {
1431             maxPoolSize = Integer.max(parallelism, 256);
1432         }
1433         if (minRunnableValue != null) {
1434             minRunnable = Integer.parseInt(minRunnableValue);
1435         } else {
1436             minRunnable = Integer.max(parallelism / 2, 1);

   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 package java.lang;
  26 
  27 import java.lang.reflect.Constructor;
  28 import java.util.Arrays;
  29 import java.util.Locale;
  30 import java.util.Objects;
  31 import java.util.concurrent.CountDownLatch;
  32 import java.util.concurrent.Executor;
  33 import java.util.concurrent.Executors;
  34 import java.util.concurrent.ForkJoinPool;
  35 import java.util.concurrent.ForkJoinPool.ForkJoinWorkerThreadFactory;
  36 import java.util.concurrent.ForkJoinTask;
  37 import java.util.concurrent.Future;
  38 import java.util.concurrent.RejectedExecutionException;
  39 import java.util.concurrent.ScheduledExecutorService;
  40 import java.util.concurrent.ScheduledThreadPoolExecutor;
  41 import java.util.concurrent.TimeUnit;
  42 import java.util.stream.Stream;
  43 import jdk.internal.event.VirtualThreadEndEvent;
  44 import jdk.internal.event.VirtualThreadStartEvent;
  45 import jdk.internal.event.VirtualThreadSubmitFailedEvent;
  46 import jdk.internal.misc.CarrierThread;
  47 import jdk.internal.misc.InnocuousThread;

  49 import jdk.internal.vm.Continuation;
  50 import jdk.internal.vm.ContinuationScope;
  51 import jdk.internal.vm.StackableScope;
  52 import jdk.internal.vm.ThreadContainer;
  53 import jdk.internal.vm.ThreadContainers;
  54 import jdk.internal.vm.annotation.ChangesCurrentThread;
  55 import jdk.internal.vm.annotation.Hidden;
  56 import jdk.internal.vm.annotation.IntrinsicCandidate;
  57 import jdk.internal.vm.annotation.JvmtiHideEvents;
  58 import jdk.internal.vm.annotation.JvmtiMountTransition;
  59 import jdk.internal.vm.annotation.ReservedStackAccess;
  60 import sun.nio.ch.Interruptible;
  61 import static java.util.concurrent.TimeUnit.*;
  62 
  63 /**
  64  * A thread that is scheduled by the Java virtual machine rather than the operating system.
  65  */
  66 final class VirtualThread extends BaseVirtualThread {
  67     private static final Unsafe U = Unsafe.getUnsafe();
  68     private static final ContinuationScope VTHREAD_SCOPE = new ContinuationScope("VirtualThreads");
  69     private static final Executor DEFAULT_SCHEDULER = createDefaultScheduler();
  70     private static final ScheduledExecutorService[] DELAYED_TASK_SCHEDULERS = createDelayedTaskSchedulers();
  71 
  72     private static final long STATE = U.objectFieldOffset(VirtualThread.class, "state");
  73     private static final long PARK_PERMIT = U.objectFieldOffset(VirtualThread.class, "parkPermit");
  74     private static final long CARRIER_THREAD = U.objectFieldOffset(VirtualThread.class, "carrierThread");
  75     private static final long TERMINATION = U.objectFieldOffset(VirtualThread.class, "termination");
  76     private static final long ON_WAITING_LIST = U.objectFieldOffset(VirtualThread.class, "onWaitingList");
  77 
  78     // scheduler and continuation
  79     private final Executor scheduler;
  80     private final Continuation cont;
  81     private final Runnable runContinuation;
  82 
  83     // virtual thread state, accessed by VM
  84     private volatile int state;
  85 
  86     /*
  87      * Virtual thread state transitions:
  88      *
  89      *      NEW -> STARTED         // Thread.start, schedule to run

1394 
1395     @IntrinsicCandidate
1396     @JvmtiMountTransition
1397     private native void notifyJvmtiMount(boolean hide);
1398 
1399     @IntrinsicCandidate
1400     @JvmtiMountTransition
1401     private native void notifyJvmtiUnmount(boolean hide);
1402 
1403     @IntrinsicCandidate
1404     private static native void notifyJvmtiDisableSuspend(boolean enter);
1405 
1406     private static native void registerNatives();
1407     static {
1408         registerNatives();
1409 
1410         // ensure VTHREAD_GROUP is created, may be accessed by JVMTI
1411         var group = Thread.virtualThreadGroup();
1412     }
1413 
1414     /**
1415      * Creates the default scheduler.
1416      * If the system property {@code jdk.virtualThreadScheduler.implClass} is set then
1417      * its value is the name of a class that implements java.util.concurrent.Executor.
1418      * The class is public in an exported package, has a public no-arg constructor,
1419      * and is visible to the system class loader.
1420      * If the system property is not set then the default scheduler will be a
1421      * ForkJoinPool instance.
1422      */
1423     private static Executor createDefaultScheduler() {
1424         String propValue = System.getProperty("jdk.virtualThreadScheduler.implClass");
1425         if (propValue != null) {
1426             try {
1427                 Class<?> clazz = Class.forName(propValue, true,
1428                         ClassLoader.getSystemClassLoader());
1429                 Constructor<?> ctor = clazz.getConstructor();
1430                 var scheduler = (Executor) ctor.newInstance();
1431                 System.err.println("""
1432                     WARNING: Using custom scheduler, this is an experimental feature.""");
1433                 return scheduler;
1434             } catch (Exception ex) {
1435                 throw new Error(ex);
1436             }
1437         } else {
1438             return createDefaultForkJoinPoolScheduler();
1439         }
1440     }
1441 
1442     /**
1443      * Creates the default ForkJoinPool scheduler.
1444      */
1445     private static ForkJoinPool createDefaultForkJoinPoolScheduler() {
1446         ForkJoinWorkerThreadFactory factory = pool -> new CarrierThread(pool);
1447         int parallelism, maxPoolSize, minRunnable;
1448         String parallelismValue = System.getProperty("jdk.virtualThreadScheduler.parallelism");
1449         String maxPoolSizeValue = System.getProperty("jdk.virtualThreadScheduler.maxPoolSize");
1450         String minRunnableValue = System.getProperty("jdk.virtualThreadScheduler.minRunnable");
1451         if (parallelismValue != null) {
1452             parallelism = Integer.parseInt(parallelismValue);
1453         } else {
1454             parallelism = Runtime.getRuntime().availableProcessors();
1455         }
1456         if (maxPoolSizeValue != null) {
1457             maxPoolSize = Integer.parseInt(maxPoolSizeValue);
1458             parallelism = Integer.min(parallelism, maxPoolSize);
1459         } else {
1460             maxPoolSize = Integer.max(parallelism, 256);
1461         }
1462         if (minRunnableValue != null) {
1463             minRunnable = Integer.parseInt(minRunnableValue);
1464         } else {
1465             minRunnable = Integer.max(parallelism / 2, 1);
< prev index next >