1 /* 2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 3 * 4 * This code is free software; you can redistribute it and/or modify it 5 * under the terms of the GNU General Public License version 2 only, as 6 * published by the Free Software Foundation. 7 * 8 * This code is distributed in the hope that it will be useful, but WITHOUT 9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 11 * version 2 for more details (a copy is included in the LICENSE file that 12 * accompanied this code). 13 * 14 * You should have received a copy of the GNU General Public License version 15 * 2 along with this work; if not, write to the Free Software Foundation, 16 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 17 * 18 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 19 * or visit www.oracle.com if you need additional information or have any 20 * questions. 21 */ 22 23 /* 24 * This file is available under and governed by the GNU General Public 25 * License version 2 only, as published by the Free Software Foundation. 26 * However, the following notice accompanied the original version of this 27 * file: 28 * 29 * Written by Doug Lea with assistance from members of JCP JSR-166 30 * Expert Group and released to the public domain, as explained at 31 * http://creativecommons.org/publicdomain/zero/1.0/ 32 */ 33 34 package test.java.util.concurrent.tck; 35 36 import static java.util.concurrent.TimeUnit.MILLISECONDS; 37 import static java.util.concurrent.TimeUnit.SECONDS; 38 import static org.junit.Assert.assertEquals; 39 import static org.junit.Assert.assertTrue; 40 41 import java.util.concurrent.ForkJoinPool; 42 import java.util.concurrent.ForkJoinTask; 43 import java.util.concurrent.ForkJoinWorkerThread; 44 import java.util.concurrent.Future; 45 import java.util.concurrent.RejectedExecutionException; 46 import java.util.concurrent.atomic.AtomicReference; 47 import java.util.concurrent.locks.LockSupport; 48 49 import org.junit.Test; 50 import org.junit.runner.RunWith; 51 import org.junit.runners.JUnit4; 52 53 /** 54 * Tests for ForkJoinPool and ForkJoinWorkerThread additions in JDK 20. 55 */ 56 // Android-changed: Use JUnit4. 57 @RunWith(JUnit4.class) 58 public class ForkJoinPool20Test extends JSR166TestCase { 59 // Android-changed: Use JUnitCore.main. main(String[] args)60 public static void main(String[] args) { 61 // main(suite(), args); 62 org.junit.runner.JUnitCore.main("test.java.util.concurrent.tck.ForkJoinPool20Test"); 63 } 64 65 // public static Test suite() { 66 // return new TestSuite(ForkJoinPool20Test.class); 67 // } 68 69 /** 70 * Test that tasks submitted with externalSubmit execute. 71 */ 72 @Test testExternalSubmit1()73 public void testExternalSubmit1() throws Exception { 74 try (var pool = new ForkJoinPool()) { 75 // submit from external client 76 var task1 = ForkJoinTask.adapt(() -> "foo"); 77 pool.externalSubmit(task1); 78 assertEquals(task1.get(), "foo"); 79 80 // submit from worker thread 81 Future<Future<String>> task2 = pool.submit(() -> { 82 return pool.externalSubmit(ForkJoinTask.adapt(() -> "foo")); 83 }); 84 assertEquals(task2.get().get(), "foo"); 85 } 86 } 87 88 /** 89 * Test that tasks submitted with externalSubmit are pushed to a submission queue. 90 */ 91 @Test testExternalSubmit2()92 public void testExternalSubmit2() throws Exception { 93 try (var pool = new ForkJoinPool(1)) { 94 pool.submit(() -> { 95 assertTrue(pool.getQueuedTaskCount() == 0); 96 assertTrue(pool.getQueuedSubmissionCount() == 0); 97 98 for (int count = 1; count <= 3; count++) { 99 var task = ForkJoinTask.adapt(() -> { }); 100 pool.externalSubmit(task); 101 102 assertTrue(pool.getQueuedTaskCount() == 0); 103 assertTrue(pool.getQueuedSubmissionCount() == count); 104 } 105 }).get(); 106 } 107 } 108 109 /** 110 * Test externalSubmit return value. 111 */ 112 @Test testExternalSubmitReturnsTask()113 public void testExternalSubmitReturnsTask() { 114 try (var pool = new ForkJoinPool()) { 115 var task = ForkJoinTask.adapt(() -> "foo"); 116 assertTrue(pool.externalSubmit(task) == task); 117 } 118 } 119 120 /** 121 * Test externalSubmit(null) throws NullPointerException. 122 */ 123 @Test testExternalSubmitWithNull()124 public void testExternalSubmitWithNull() { 125 try (var pool = new ForkJoinPool()) { 126 assertThrows(NullPointerException.class, () -> pool.externalSubmit(null)); 127 } 128 } 129 130 /** 131 * Test externalSubmit throws RejectedExecutionException when pool is shutdown. 132 */ 133 @Test testExternalSubmitWhenShutdown()134 public void testExternalSubmitWhenShutdown() { 135 try (var pool = new ForkJoinPool()) { 136 pool.shutdown(); 137 var task = ForkJoinTask.adapt(() -> { }); 138 assertThrows(RejectedExecutionException.class, () -> pool.externalSubmit(task)); 139 } 140 } 141 142 /** 143 * Test that tasks submitted with submit(ForkJoinTask) are pushed to a 144 * submission queue. 145 */ 146 @Test testSubmit()147 public void testSubmit() throws Exception { 148 try (var pool = new ForkJoinPool(1)) { 149 ForkJoinWorkerThread worker = submitBusyTask(pool); 150 try { 151 assertTrue(worker.getQueuedTaskCount() == 0); 152 assertTrue(pool.getQueuedTaskCount() == 0); 153 assertTrue(pool.getQueuedSubmissionCount() == 0); 154 155 for (int count = 1; count <= 3; count++) { 156 var task = ForkJoinTask.adapt(() -> { }); 157 pool.submit(task); 158 159 // task should be in submission queue 160 assertTrue(worker.getQueuedTaskCount() == 0); 161 assertTrue(pool.getQueuedTaskCount() == 0); 162 assertTrue(pool.getQueuedSubmissionCount() == count); 163 } 164 } finally { 165 LockSupport.unpark(worker); 166 } 167 } 168 } 169 170 /** 171 * Test ForkJoinWorkerThread::getQueuedTaskCount returns the number of tasks in the 172 * current thread's queue. This test runs with parallelism of 1 to ensure that tasks 173 * aren't stolen. 174 */ 175 @Test testGetQueuedTaskCount1()176 public void testGetQueuedTaskCount1() throws Exception { 177 try (var pool = new ForkJoinPool(1)) { 178 pool.submit(() -> { 179 var worker = (ForkJoinWorkerThread) Thread.currentThread(); 180 assertTrue(worker.getQueuedTaskCount() == 0); 181 182 for (int count = 1; count <= 3; count++) { 183 pool.submit(() -> { }); 184 185 // task should be in this thread's task queue 186 assertTrue(worker.getQueuedTaskCount() == count); 187 assertTrue(pool.getQueuedTaskCount() == count); 188 assertTrue(pool.getQueuedSubmissionCount() == 0); 189 } 190 }).get(); 191 } 192 } 193 194 /** 195 * Test ForkJoinWorkerThread::getQueuedTaskCount returns the number of tasks in the 196 * thread's queue. This test runs with parallelism of 2 and one worker active running 197 * a task. This gives the test two task queues to sample. 198 */ 199 @Test testGetQueuedTaskCount2()200 public void testGetQueuedTaskCount2() throws Exception { 201 try (var pool = new ForkJoinPool(2)) { 202 // keep one worker thread active 203 ForkJoinWorkerThread worker1 = submitBusyTask(pool); 204 try { 205 pool.submit(() -> { 206 var worker2 = (ForkJoinWorkerThread) Thread.currentThread(); 207 for (int count = 1; count <= 3; count++) { 208 pool.submit(() -> { }); 209 210 // task should be in this thread's task queue 211 assertTrue(worker1.getQueuedTaskCount() == 0); 212 assertTrue(worker2.getQueuedTaskCount() == count); 213 assertTrue(pool.getQueuedTaskCount() == count); 214 assertTrue(pool.getQueuedSubmissionCount() == 0); 215 } 216 }).get(); 217 } finally { 218 LockSupport.unpark(worker1); // release worker1 219 } 220 } 221 } 222 223 /** 224 * Submits a task to the pool, returning the worker thread that runs the 225 * task. The task runs until the thread is unparked. 226 */ submitBusyTask(ForkJoinPool pool)227 static ForkJoinWorkerThread submitBusyTask(ForkJoinPool pool) throws Exception { 228 var ref = new AtomicReference<ForkJoinWorkerThread>(); 229 pool.submit(() -> { 230 ref.set((ForkJoinWorkerThread) Thread.currentThread()); 231 LockSupport.park(); 232 }); 233 ForkJoinWorkerThread worker; 234 while ((worker = ref.get()) == null) { 235 Thread.sleep(20); 236 } 237 return worker; 238 } 239 } 240