1 /* 2 * Copyright (c) 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 26 * @summary Test cancelling a timeout task for Object.wait(millis) when there is 27 * contention on the timer queue 28 * @key randomness 29 * @run main/othervm 30 * -Djdk.virtualThreadScheduler.parallelism=2 31 * -Djdk.virtualThreadScheduler.timerQueues=1 32 * CancelTimerWithContention 33 */ 34 35 import java.time.Instant; 36 import java.util.Random; 37 import java.util.concurrent.Executors; 38 import java.util.concurrent.atomic.AtomicInteger; 39 40 public class CancelTimerWithContention { 41 42 // number of threads 43 private static final int MIN_THREADS = 100; 44 private static final int MAX_THREADS = 10_000; 45 46 // number of monitors to enter 47 private static final int MIN_MONITORS = 2; 48 private static final int MAX_MONITORS = 8; 49 50 private static final Random RAND = new Random(); 51 52 public static void main(String[] args) { 53 for (int threadCount = MIN_THREADS; threadCount <= MAX_THREADS; threadCount += 100) { 54 System.out.format("%s #threads = %d%n", Instant.now(), threadCount); 55 for (int lockCount = MIN_MONITORS; lockCount <= MAX_MONITORS; lockCount += 2) { 56 test(threadCount, lockCount); 57 } 58 } 59 } 60 61 /** 62 * Test threads entering monitors and using Object.wait(millis) to wait. This 63 * testing scenario leads to a mix of contention (with responsible threads using 64 * short timeouts), timed-wait, and cancellation of timer tasks. This scenario 65 * can result in contention of the timer queue. 66 */ 67 static void test(int threadCount, int monitorCount) { 68 var locks = new Object[monitorCount]; 69 for (int i = 0; i < monitorCount; i++) { 70 locks[i] = new Object(); 71 } 72 73 try (var executor = Executors.newVirtualThreadPerTaskExecutor()) { 74 var finished = new AtomicInteger(); 75 76 for (int i = 0; i < threadCount; i++) { 77 Object lock = locks[RAND.nextInt(monitorCount)]; // random lock 78 79 executor.submit(() -> { 80 synchronized (lock) { 81 lock.wait(Long.MAX_VALUE); 82 } 83 finished.incrementAndGet(); 84 return null; 85 }); 86 87 synchronized (lock) { 88 lock.notify(); 89 } 90 } 91 92 // notify at most one thread until all threads are finished 93 while (finished.get() < threadCount) { 94 for (Object lock : locks) { 95 synchronized (lock) { 96 lock.notify(); 97 } 98 } 99 } 100 } 101 } 102 }