< 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.security.AccessController;
  28 import java.security.PrivilegedAction;
  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.ForkJoinWorkerThread;
  38 import java.util.concurrent.Future;
  39 import java.util.concurrent.RejectedExecutionException;
  40 import java.util.concurrent.ScheduledExecutorService;
  41 import java.util.concurrent.ScheduledThreadPoolExecutor;
  42 import jdk.internal.event.ThreadSleepEvent;
  43 import jdk.internal.event.VirtualThreadEndEvent;
  44 import jdk.internal.event.VirtualThreadPinnedEvent;
  45 import jdk.internal.event.VirtualThreadStartEvent;
  46 import jdk.internal.event.VirtualThreadSubmitFailedEvent;
  47 import jdk.internal.misc.CarrierThread;
  48 import jdk.internal.misc.InnocuousThread;
  49 import jdk.internal.misc.Unsafe;
  50 import jdk.internal.vm.Continuation;
  51 import jdk.internal.vm.ContinuationScope;
  52 import jdk.internal.vm.StackableScope;
  53 import jdk.internal.vm.ThreadContainer;
  54 import jdk.internal.vm.ThreadContainers;
  55 import jdk.internal.vm.annotation.ChangesCurrentThread;


  56 import jdk.internal.vm.annotation.JvmtiMountTransition;
  57 import sun.nio.ch.Interruptible;
  58 import sun.security.action.GetPropertyAction;
  59 import static java.util.concurrent.TimeUnit.*;
  60 
  61 /**
  62  * A thread that is scheduled by the Java virtual machine rather than the operating
  63  * 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 UNPARKER = createDelayedTaskScheduler();
  70     private static final int TRACE_PINNING_MODE = tracePinningMode();
  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");

 253         submitRunContinuation(false);
 254     }
 255 
 256     /**
 257      * Submits the runContinuation task to the scheduler and without signalling
 258      * any threads if possible.
 259      * @throws RejectedExecutionException
 260      */
 261     private void lazySubmitRunContinuation() {
 262         submitRunContinuation(true);
 263     }
 264 
 265     /**
 266      * Runs a task in the context of this virtual thread. The virtual thread is
 267      * mounted on the current (carrier) thread before the task runs. It unmounts
 268      * from its carrier thread when the task completes.
 269      */
 270     @ChangesCurrentThread
 271     private void run(Runnable task) {
 272         assert state == RUNNING;
 273         boolean notifyJvmti = notifyJvmtiEvents;
 274 
 275         // first mount
 276         mount();
 277         if (notifyJvmti) notifyJvmtiMountEnd(true);
 278 
 279         // emit JFR event if enabled
 280         if (VirtualThreadStartEvent.isTurnedOn()) {
 281             var event = new VirtualThreadStartEvent();
 282             event.javaThreadId = threadId();
 283             event.commit();
 284         }
 285 

 286         try {
 287             task.run();
 288         } catch (Throwable exc) {
 289             dispatchUncaughtException(exc);
 290         } finally {
 291             try {
 292 
 293                 // pop any remaining scopes from the stack, this may block
 294                 StackableScope.popAll();
 295 
 296                 // emit JFR event if enabled
 297                 if (VirtualThreadEndEvent.isTurnedOn()) {
 298                     var event = new VirtualThreadEndEvent();
 299                     event.javaThreadId = threadId();
 300                     event.commit();
 301                 }
 302 
 303             } finally {
 304                 // last unmount
 305                 if (notifyJvmti) notifyJvmtiUnmountBegin(true);
 306                 unmount();
 307 
 308                 // final state
 309                 setState(TERMINATED);
 310             }
 311         }
 312     }
 313 








 314     /**
 315      * Mounts this virtual thread onto the current platform thread. On
 316      * return, the current thread is the virtual thread.
 317      */
 318     @ChangesCurrentThread
 319     private void mount() {
 320         // sets the carrier thread
 321         Thread carrier = Thread.currentCarrierThread();
 322         setCarrierThread(carrier);
 323 
 324         // sync up carrier thread interrupt status if needed
 325         if (interrupted) {
 326             carrier.setInterrupt();
 327         } else if (carrier.isInterrupted()) {
 328             synchronized (interruptLock) {
 329                 // need to recheck interrupt status
 330                 if (!interrupted) {
 331                     carrier.clearInterrupt();
 332                 }
 333             }

 377      * If {@code notifyJvmti} is true then JVMTI is notified.
 378      */
 379     @ChangesCurrentThread
 380     @JvmtiMountTransition
 381     private void switchToVirtualThread(VirtualThread vthread, boolean notifyJvmti) {
 382         Thread carrier = vthread.carrierThread;
 383         assert carrier == Thread.currentCarrierThread();
 384         carrier.setCurrentThread(vthread);
 385         if (notifyJvmti) {
 386             notifyJvmtiHideFrames(false);
 387         }
 388     }
 389 
 390     /**
 391      * Unmounts this virtual thread, invokes Continuation.yield, and re-mounts the
 392      * thread when continued. When enabled, JVMTI must be notified from this method.
 393      * @return true if the yield was successful
 394      */
 395     @ChangesCurrentThread
 396     private boolean yieldContinuation() {
 397         boolean notifyJvmti = notifyJvmtiEvents;
 398 
 399         // unmount
 400         if (notifyJvmti) notifyJvmtiUnmountBegin(false);
 401         unmount();
 402         try {
 403             return Continuation.yield(VTHREAD_SCOPE);
 404         } finally {
 405             // re-mount
 406             mount();
 407             if (notifyJvmti) notifyJvmtiMountEnd(false);
 408         }
 409     }
 410 
 411     /**
 412      * Invoked after the continuation yields. If parking then it sets the state
 413      * and also re-submits the task to continue if unparked while parking.
 414      * If yielding due to Thread.yield then it just submits the task to continue.
 415      */
 416     private void afterYield() {
 417         int s = state();
 418         assert (s == PARKING || s == YIELDING) && (carrierThread == null);
 419 
 420         if (s == PARKING) {
 421             setState(PARKED);
 422 
 423             // notify JVMTI that unmount has completed, thread is parked
 424             if (notifyJvmtiEvents) notifyJvmtiUnmountEnd(false);
 425 
 426             // may have been unparked while parking
 427             if (parkPermit && compareAndSetState(PARKED, RUNNABLE)) {

 471     /**
 472      * Schedules this {@code VirtualThread} to execute.
 473      *
 474      * @throws IllegalStateException if the container is shutdown or closed
 475      * @throws IllegalThreadStateException if the thread has already been started
 476      * @throws RejectedExecutionException if the scheduler cannot accept a task
 477      */
 478     @Override
 479     void start(ThreadContainer container) {
 480         if (!compareAndSetState(NEW, STARTED)) {
 481             throw new IllegalThreadStateException("Already started");
 482         }
 483 
 484         // bind thread to container
 485         setThreadContainer(container);
 486 
 487         // start thread
 488         boolean started = false;
 489         container.onStart(this); // may throw
 490         try {
 491             // extent locals may be inherited
 492             inheritExtentLocalBindings(container);
 493 
 494             // submit task to run thread
 495             submitRunContinuation();
 496             started = true;
 497         } finally {
 498             if (!started) {
 499                 setState(TERMINATED);
 500                 container.onExit(this);
 501                 afterTerminate(/*executed*/ false);
 502             }
 503         }
 504     }
 505 
 506     @Override
 507     public void start() {
 508         start(ThreadContainers.root());
 509     }
 510 
 511     @Override
 512     public void run() {

   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.ref.Reference;
  28 import java.security.AccessController;
  29 import java.security.PrivilegedAction;
  30 import java.util.Locale;
  31 import java.util.Objects;
  32 import java.util.concurrent.CountDownLatch;
  33 import java.util.concurrent.Executor;
  34 import java.util.concurrent.Executors;
  35 import java.util.concurrent.ForkJoinPool;
  36 import java.util.concurrent.ForkJoinPool.ForkJoinWorkerThreadFactory;
  37 import java.util.concurrent.ForkJoinTask;
  38 import java.util.concurrent.ForkJoinWorkerThread;
  39 import java.util.concurrent.Future;
  40 import java.util.concurrent.RejectedExecutionException;
  41 import java.util.concurrent.ScheduledExecutorService;
  42 import java.util.concurrent.ScheduledThreadPoolExecutor;
  43 import jdk.internal.event.ThreadSleepEvent;
  44 import jdk.internal.event.VirtualThreadEndEvent;
  45 import jdk.internal.event.VirtualThreadPinnedEvent;
  46 import jdk.internal.event.VirtualThreadStartEvent;
  47 import jdk.internal.event.VirtualThreadSubmitFailedEvent;
  48 import jdk.internal.misc.CarrierThread;
  49 import jdk.internal.misc.InnocuousThread;
  50 import jdk.internal.misc.Unsafe;
  51 import jdk.internal.vm.Continuation;
  52 import jdk.internal.vm.ContinuationScope;
  53 import jdk.internal.vm.StackableScope;
  54 import jdk.internal.vm.ThreadContainer;
  55 import jdk.internal.vm.ThreadContainers;
  56 import jdk.internal.vm.annotation.ChangesCurrentThread;
  57 import jdk.internal.vm.annotation.ForceInline;
  58 import jdk.internal.vm.annotation.Hidden;
  59 import jdk.internal.vm.annotation.JvmtiMountTransition;
  60 import sun.nio.ch.Interruptible;
  61 import sun.security.action.GetPropertyAction;
  62 import static java.util.concurrent.TimeUnit.*;
  63 
  64 /**
  65  * A thread that is scheduled by the Java virtual machine rather than the operating
  66  * system.
  67  */
  68 final class VirtualThread extends BaseVirtualThread {
  69     private static final Unsafe U = Unsafe.getUnsafe();
  70     private static final ContinuationScope VTHREAD_SCOPE = new ContinuationScope("VirtualThreads");
  71     private static final ForkJoinPool DEFAULT_SCHEDULER = createDefaultScheduler();
  72     private static final ScheduledExecutorService UNPARKER = createDelayedTaskScheduler();
  73     private static final int TRACE_PINNING_MODE = tracePinningMode();
  74 
  75     private static final long STATE = U.objectFieldOffset(VirtualThread.class, "state");
  76     private static final long PARK_PERMIT = U.objectFieldOffset(VirtualThread.class, "parkPermit");
  77     private static final long CARRIER_THREAD = U.objectFieldOffset(VirtualThread.class, "carrierThread");
  78     private static final long TERMINATION = U.objectFieldOffset(VirtualThread.class, "termination");

 256         submitRunContinuation(false);
 257     }
 258 
 259     /**
 260      * Submits the runContinuation task to the scheduler and without signalling
 261      * any threads if possible.
 262      * @throws RejectedExecutionException
 263      */
 264     private void lazySubmitRunContinuation() {
 265         submitRunContinuation(true);
 266     }
 267 
 268     /**
 269      * Runs a task in the context of this virtual thread. The virtual thread is
 270      * mounted on the current (carrier) thread before the task runs. It unmounts
 271      * from its carrier thread when the task completes.
 272      */
 273     @ChangesCurrentThread
 274     private void run(Runnable task) {
 275         assert state == RUNNING;

 276 
 277         // first mount
 278         mount();
 279         if (notifyJvmtiEvents) notifyJvmtiMountEnd(true);
 280 
 281         // emit JFR event if enabled
 282         if (VirtualThreadStartEvent.isTurnedOn()) {
 283             var event = new VirtualThreadStartEvent();
 284             event.javaThreadId = threadId();
 285             event.commit();
 286         }
 287 
 288         Object bindings = scopedValueBindings();
 289         try {
 290             runWith(bindings, task);
 291         } catch (Throwable exc) {
 292             dispatchUncaughtException(exc);
 293         } finally {
 294             try {

 295                 // pop any remaining scopes from the stack, this may block
 296                 StackableScope.popAll();
 297 
 298                 // emit JFR event if enabled
 299                 if (VirtualThreadEndEvent.isTurnedOn()) {
 300                     var event = new VirtualThreadEndEvent();
 301                     event.javaThreadId = threadId();
 302                     event.commit();
 303                 }
 304 
 305             } finally {
 306                 // last unmount
 307                 if (notifyJvmtiEvents) notifyJvmtiUnmountBegin(true);
 308                 unmount();
 309 
 310                 // final state
 311                 setState(TERMINATED);
 312             }
 313         }
 314     }
 315 
 316     @Hidden
 317     @ForceInline
 318     private void runWith(Object bindings, Runnable op) {
 319         ensureMaterializedForStackWalk(bindings);
 320         op.run();
 321         Reference.reachabilityFence(bindings);
 322     }
 323 
 324     /**
 325      * Mounts this virtual thread onto the current platform thread. On
 326      * return, the current thread is the virtual thread.
 327      */
 328     @ChangesCurrentThread
 329     private void mount() {
 330         // sets the carrier thread
 331         Thread carrier = Thread.currentCarrierThread();
 332         setCarrierThread(carrier);
 333 
 334         // sync up carrier thread interrupt status if needed
 335         if (interrupted) {
 336             carrier.setInterrupt();
 337         } else if (carrier.isInterrupted()) {
 338             synchronized (interruptLock) {
 339                 // need to recheck interrupt status
 340                 if (!interrupted) {
 341                     carrier.clearInterrupt();
 342                 }
 343             }

 387      * If {@code notifyJvmti} is true then JVMTI is notified.
 388      */
 389     @ChangesCurrentThread
 390     @JvmtiMountTransition
 391     private void switchToVirtualThread(VirtualThread vthread, boolean notifyJvmti) {
 392         Thread carrier = vthread.carrierThread;
 393         assert carrier == Thread.currentCarrierThread();
 394         carrier.setCurrentThread(vthread);
 395         if (notifyJvmti) {
 396             notifyJvmtiHideFrames(false);
 397         }
 398     }
 399 
 400     /**
 401      * Unmounts this virtual thread, invokes Continuation.yield, and re-mounts the
 402      * thread when continued. When enabled, JVMTI must be notified from this method.
 403      * @return true if the yield was successful
 404      */
 405     @ChangesCurrentThread
 406     private boolean yieldContinuation() {


 407         // unmount
 408         if (notifyJvmtiEvents) notifyJvmtiUnmountBegin(false);
 409         unmount();
 410         try {
 411             return Continuation.yield(VTHREAD_SCOPE);
 412         } finally {
 413             // re-mount
 414             mount();
 415             if (notifyJvmtiEvents) notifyJvmtiMountEnd(false);
 416         }
 417     }
 418 
 419     /**
 420      * Invoked after the continuation yields. If parking then it sets the state
 421      * and also re-submits the task to continue if unparked while parking.
 422      * If yielding due to Thread.yield then it just submits the task to continue.
 423      */
 424     private void afterYield() {
 425         int s = state();
 426         assert (s == PARKING || s == YIELDING) && (carrierThread == null);
 427 
 428         if (s == PARKING) {
 429             setState(PARKED);
 430 
 431             // notify JVMTI that unmount has completed, thread is parked
 432             if (notifyJvmtiEvents) notifyJvmtiUnmountEnd(false);
 433 
 434             // may have been unparked while parking
 435             if (parkPermit && compareAndSetState(PARKED, RUNNABLE)) {

 479     /**
 480      * Schedules this {@code VirtualThread} to execute.
 481      *
 482      * @throws IllegalStateException if the container is shutdown or closed
 483      * @throws IllegalThreadStateException if the thread has already been started
 484      * @throws RejectedExecutionException if the scheduler cannot accept a task
 485      */
 486     @Override
 487     void start(ThreadContainer container) {
 488         if (!compareAndSetState(NEW, STARTED)) {
 489             throw new IllegalThreadStateException("Already started");
 490         }
 491 
 492         // bind thread to container
 493         setThreadContainer(container);
 494 
 495         // start thread
 496         boolean started = false;
 497         container.onStart(this); // may throw
 498         try {
 499             // scoped values may be inherited
 500             inheritScopedValueBindings(container);
 501 
 502             // submit task to run thread
 503             submitRunContinuation();
 504             started = true;
 505         } finally {
 506             if (!started) {
 507                 setState(TERMINATED);
 508                 container.onExit(this);
 509                 afterTerminate(/*executed*/ false);
 510             }
 511         }
 512     }
 513 
 514     @Override
 515     public void start() {
 516         start(ThreadContainers.root());
 517     }
 518 
 519     @Override
 520     public void run() {
< prev index next >