< prev index next >

test/jdk/java/lang/Thread/virtual/Parking.java

Print this page

  1 /*
  2  * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved.
  3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  4  *
  5  * This code is free software; you can redistribute it and/or modify it
  6  * under the terms of the GNU General Public License version 2 only, as
  7  * published by the Free Software Foundation.
  8  *
  9  * This code is distributed in the hope that it will be useful, but WITHOUT
 10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 12  * version 2 for more details (a copy is included in the LICENSE file that
 13  * accompanied this code).
 14  *
 15  * You should have received a copy of the GNU General Public License version
 16  * 2 along with this work; if not, write to the Free Software Foundation,
 17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 18  *
 19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 20  * or visit www.oracle.com if you need additional information or have any
 21  * questions.
 22  */
 23 
 24 /**
 25  * @test
 26  * @summary Test virtual threads using park/unpark


 27  * @library /test/lib

 28  * @run junit Parking
 29  */
 30 



























 31 import java.time.Duration;




 32 import java.util.concurrent.TimeUnit;

 33 import java.util.concurrent.locks.LockSupport;
 34 
 35 import jdk.test.lib.thread.VThreadRunner;

 36 import org.junit.jupiter.api.Test;



 37 import static org.junit.jupiter.api.Assertions.*;

 38 
 39 class Parking {
 40     private static final Object lock = new Object();

 41 
 42     /**
 43      * Park, unparked by platform thread.
 44      */
 45     @Test
 46     void testPark1() throws Exception {
 47         var thread = Thread.ofVirtual().start(LockSupport::park);
 48         Thread.sleep(1000); // give time for virtual thread to park
 49         LockSupport.unpark(thread);
 50         thread.join();
 51     }
 52 
 53     /**
 54      * Park, unparked by virtual thread.
 55      */
 56     @Test
 57     void testPark2() throws Exception {
 58         var thread1 = Thread.ofVirtual().start(LockSupport::park);
 59         Thread.sleep(1000); // give time for virtual thread to park
 60         var thread2 = Thread.ofVirtual().start(() -> LockSupport.unpark(thread1));

326             assertTrue(t.isInterrupted());
327         });
328     }
329 
330     /**
331      * Thread interrupt when parked in parkNanos and while holding monitor.
332      */
333     @Test
334     void testParkNanos11() throws Exception {
335         VThreadRunner.run(() -> {
336             Thread t = Thread.currentThread();
337             scheduleInterrupt(t, 1000);
338             while (!Thread.currentThread().isInterrupted()) {
339                 synchronized (lock) {
340                     LockSupport.parkNanos(Duration.ofDays(1).toNanos());
341                 }
342             }
343         });
344     }
345 





















































































346     /**
347      * Schedule a thread to be interrupted after a delay.
348      */
349     private static void scheduleInterrupt(Thread thread, long delay) {
350         Runnable interruptTask = () -> {
351             try {
352                 Thread.sleep(delay);
353                 thread.interrupt();
354             } catch (Exception e) {
355                 e.printStackTrace();
356             }
357         };
358         new Thread(interruptTask).start();
359     }












360 }

  1 /*
  2  * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved.
  3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  4  *
  5  * This code is free software; you can redistribute it and/or modify it
  6  * under the terms of the GNU General Public License version 2 only, as
  7  * published by the Free Software Foundation.
  8  *
  9  * This code is distributed in the hope that it will be useful, but WITHOUT
 10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 12  * version 2 for more details (a copy is included in the LICENSE file that
 13  * accompanied this code).
 14  *
 15  * You should have received a copy of the GNU General Public License version
 16  * 2 along with this work; if not, write to the Free Software Foundation,
 17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 18  *
 19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 20  * or visit www.oracle.com if you need additional information or have any
 21  * questions.
 22  */
 23 
 24 /*
 25  * @test id=default
 26  * @summary Test virtual threads using park/unpark
 27  * @requires os.arch=="amd64" | os.arch=="x86_64" | os.arch=="aarch64" | os.arch=="riscv64"
 28  * @modules java.base/java.lang:+open jdk.management
 29  * @library /test/lib
 30  * @build LockingMode
 31  * @run junit Parking
 32  */
 33 
 34 /*
 35  * @test id=Xint
 36  * @requires os.arch=="amd64" | os.arch=="x86_64" | os.arch=="aarch64" | os.arch=="riscv64"
 37  * @modules java.base/java.lang:+open jdk.management
 38  * @library /test/lib
 39  * @build LockingMode
 40  * @run junit/othervm -Xint Parking
 41  */
 42 
 43 /*
 44  * @test id=Xcomp
 45  * @requires os.arch=="amd64" | os.arch=="x86_64" | os.arch=="aarch64" | os.arch=="riscv64"
 46  * @modules java.base/java.lang:+open jdk.management
 47  * @library /test/lib
 48  * @build LockingMode
 49  * @run junit/othervm -Xcomp Parking
 50  */
 51 
 52 /*
 53  * @test id=Xcomp-noTieredCompilation
 54  * @requires os.arch=="amd64" | os.arch=="x86_64" | os.arch=="aarch64" | os.arch=="riscv64"
 55  * @modules java.base/java.lang:+open jdk.management
 56  * @library /test/lib
 57  * @build LockingMode
 58  * @run junit/othervm -Xcomp -XX:-TieredCompilation Parking
 59  */
 60 
 61 import java.time.Duration;
 62 import java.util.concurrent.Executors;
 63 import java.util.concurrent.ExecutorService;
 64 import java.util.concurrent.CountDownLatch;
 65 import java.util.concurrent.ThreadFactory;
 66 import java.util.concurrent.TimeUnit;
 67 import java.util.concurrent.atomic.AtomicBoolean;
 68 import java.util.concurrent.locks.LockSupport;
 69 
 70 import jdk.test.lib.thread.VThreadRunner;
 71 import jdk.test.lib.thread.VThreadScheduler;
 72 import org.junit.jupiter.api.Test;
 73 import org.junit.jupiter.api.condition.DisabledIf;
 74 import org.junit.jupiter.params.ParameterizedTest;
 75 import org.junit.jupiter.params.provider.ValueSource;
 76 import static org.junit.jupiter.api.Assertions.*;
 77 import static org.junit.jupiter.api.Assumptions.*;
 78 
 79 class Parking {
 80     static final int MAX_VTHREAD_COUNT = 4 * Runtime.getRuntime().availableProcessors();
 81     static final Object lock = new Object();
 82 
 83     /**
 84      * Park, unparked by platform thread.
 85      */
 86     @Test
 87     void testPark1() throws Exception {
 88         var thread = Thread.ofVirtual().start(LockSupport::park);
 89         Thread.sleep(1000); // give time for virtual thread to park
 90         LockSupport.unpark(thread);
 91         thread.join();
 92     }
 93 
 94     /**
 95      * Park, unparked by virtual thread.
 96      */
 97     @Test
 98     void testPark2() throws Exception {
 99         var thread1 = Thread.ofVirtual().start(LockSupport::park);
100         Thread.sleep(1000); // give time for virtual thread to park
101         var thread2 = Thread.ofVirtual().start(() -> LockSupport.unpark(thread1));

367             assertTrue(t.isInterrupted());
368         });
369     }
370 
371     /**
372      * Thread interrupt when parked in parkNanos and while holding monitor.
373      */
374     @Test
375     void testParkNanos11() throws Exception {
376         VThreadRunner.run(() -> {
377             Thread t = Thread.currentThread();
378             scheduleInterrupt(t, 1000);
379             while (!Thread.currentThread().isInterrupted()) {
380                 synchronized (lock) {
381                     LockSupport.parkNanos(Duration.ofDays(1).toNanos());
382                 }
383             }
384         });
385     }
386 
387     /**
388      * Test that parking while holding a monitor releases the carrier.
389      */
390     @ParameterizedTest
391     @ValueSource(booleans = { true, false })
392     @DisabledIf("LockingMode#isLegacy")
393     void testParkWhenHoldingMonitor(boolean reenter) throws Exception {
394         assumeTrue(VThreadScheduler.supportsCustomScheduler(), "No support for custom schedulers");
395         try (ExecutorService scheduler = Executors.newFixedThreadPool(1)) {
396             ThreadFactory factory = VThreadScheduler.virtualThreadFactory(scheduler);
397 
398             var lock = new Object();
399 
400             // thread enters (and maybe reenters) a monitor and parks
401             var started = new CountDownLatch(1);
402             var vthread1 = factory.newThread(() -> {
403                 started.countDown();
404                 synchronized (lock) {
405                     if (reenter) {
406                         synchronized (lock) {
407                             LockSupport.park();
408                         }
409                     } else {
410                         LockSupport.park();
411                     }
412                 }
413             });
414 
415             vthread1.start();
416             try {
417                 // wait for thread to start and park
418                 started.await();
419                 await(vthread1, Thread.State.WAITING);
420 
421                 // carrier should be released, use it for another thread
422                 var executed = new AtomicBoolean();
423                 var vthread2 = factory.newThread(() -> {
424                     executed.set(true);
425                 });
426                 vthread2.start();
427                 vthread2.join();
428                 assertTrue(executed.get());
429             } finally {
430                 LockSupport.unpark(vthread1);
431                 vthread1.join();
432             }
433         }
434     }
435 
436     /**
437      * Test lots of virtual threads parked while holding a monitor. If the number of
438      * virtual threads exceeds the number of carrier threads then this test will hang if
439      * parking doesn't release the carrier.
440      */
441     @Test
442     @DisabledIf("LockingMode#isLegacy")
443     void testManyParkedWhenHoldingMonitor() throws Exception {
444         Thread[] vthreads = new Thread[MAX_VTHREAD_COUNT];
445         var done = new AtomicBoolean();
446         for (int i = 0; i < MAX_VTHREAD_COUNT; i++) {
447             var lock = new Object();
448             var started = new CountDownLatch(1);
449             var vthread = Thread.ofVirtual().start(() -> {
450                 started.countDown();
451                 synchronized (lock) {
452                     while (!done.get()) {
453                         LockSupport.park();
454                     }
455                 }
456             });
457             // wait for thread to start and park
458             started.await();
459             await(vthread, Thread.State.WAITING);
460             vthreads[i] = vthread;
461         }
462 
463         // cleanup
464         done.set(true);
465         for (int i = 0; i < MAX_VTHREAD_COUNT; i++) {
466             var vthread = vthreads[i];
467             LockSupport.unpark(vthread);
468             vthread.join();
469         }
470     }
471 
472     /**
473      * Schedule a thread to be interrupted after a delay.
474      */
475     private static void scheduleInterrupt(Thread thread, long delay) {
476         Runnable interruptTask = () -> {
477             try {
478                 Thread.sleep(delay);
479                 thread.interrupt();
480             } catch (Exception e) {
481                 e.printStackTrace();
482             }
483         };
484         new Thread(interruptTask).start();
485     }
486 
487     /**
488      * Waits for the given thread to reach a given state.
489      */
490     private void await(Thread thread, Thread.State expectedState) throws InterruptedException {
491         Thread.State state = thread.getState();
492         while (state != expectedState) {
493             assertTrue(state != Thread.State.TERMINATED, "Thread has terminated");
494             Thread.sleep(10);
495             state = thread.getState();
496         }
497     }
498 }
< prev index next >