• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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