blob: c658e0c9cf100d256157f49d1a78c62f8aea3e10 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 2004 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
20 * CA 95054 USA or visit www.sun.com if you need additional information or
21 * have any questions.
22 */
23
24/*
25 * @test
26 * @bug 5014783
27 * @summary Basic unit test of thread states returned by
28 * Thread.getState().
29 *
30 * @author Mandy Chung
31 *
32 * @build ThreadStateTest
33 * @run main ThreadStateTest
34 */
35
36import java.util.concurrent.locks.LockSupport;
37import java.util.concurrent.Semaphore;
38
39public class ThreadStateTest {
40 private static boolean testFailed = false;
41
42 static class Lock {
43 private String name;
44 Lock(String name) {
45 this.name = name;
46 }
47 public String toString() {
48 return name;
49 }
50 }
51 private static Lock globalLock = new Lock("my lock");
52
53 public static void main(String[] argv) {
54 // Call Thread.getState to force all initialization done
55 // before test verification begins.
56 Thread.currentThread().getState();
57 MyThread myThread = new MyThread("MyThread");
58
59 // before myThread starts
60 checkThreadState(myThread, Thread.State.NEW);
61
62 myThread.start();
63 myThread.waitUntilStarted();
64 checkThreadState(myThread, Thread.State.RUNNABLE);
65
66 synchronized (globalLock) {
67 myThread.goBlocked();
68 checkThreadState(myThread, Thread.State.BLOCKED);
69 }
70
71 myThread.goWaiting();
72 checkThreadState(myThread, Thread.State.WAITING);
73
74 myThread.goTimedWaiting();
75 checkThreadState(myThread, Thread.State.TIMED_WAITING);
76
77
78 /*
79 *********** park and parkUntil seems not working
80 * ignore this case for now.
81 * Bug ID 5062095
82 ***********************************************
83
84 myThread.goParked();
85 checkThreadState(myThread, Thread.State.WAITING);
86
87 myThread.goTimedParked();
88 checkThreadState(myThread, Thread.State.TIMED_WAITING);
89 */
90
91
92 myThread.goSleeping();
93 checkThreadState(myThread, Thread.State.TIMED_WAITING);
94
95 myThread.terminate();
96 checkThreadState(myThread, Thread.State.TERMINATED);
97
98 try {
99 myThread.join();
100 } catch (InterruptedException e) {
101 e.printStackTrace();
102 System.out.println("Unexpected exception.");
103 testFailed = true;
104 }
105 if (testFailed)
106 throw new RuntimeException("TEST FAILED.");
107 System.out.println("Test passed.");
108 }
109
110 private static void checkThreadState(Thread t, Thread.State expected) {
111 Thread.State state = t.getState();
112 System.out.println("Checking thread state " + state);
113 if (state == null) {
114 throw new RuntimeException(t.getName() + " expected to have " +
115 expected + " but got null.");
116 }
117
118 if (state != expected) {
119 throw new RuntimeException(t.getName() + " expected to have " +
120 expected + " but got " + state);
121 }
122 }
123
124 private static String getLockName(Object lock) {
125 if (lock == null) return null;
126
127 return lock.getClass().getName() + '@' +
128 Integer.toHexString(System.identityHashCode(lock));
129 }
130
131 private static void goSleep(long ms) {
132 try {
133 Thread.sleep(ms);
134 } catch (InterruptedException e) {
135 e.printStackTrace();
136 System.out.println("Unexpected exception.");
137 testFailed = true;
138 }
139 }
140
141 static class MyThread extends Thread {
142 private ThreadExecutionSynchronizer thrsync = new ThreadExecutionSynchronizer();
143
144 MyThread(String name) {
145 super(name);
146 }
147
148 private final int RUNNABLE = 0;
149 private final int BLOCKED = 1;
150 private final int WAITING = 2;
151 private final int TIMED_WAITING = 3;
152 private final int PARKED = 4;
153 private final int TIMED_PARKED = 5;
154 private final int SLEEPING = 6;
155 private final int TERMINATE = 7;
156 private int state = RUNNABLE;
157
158 private boolean done = false;
159 public void run() {
160 // Signal main thread to continue.
161 thrsync.signal();
162 while (!done) {
163 switch (state) {
164 case RUNNABLE: {
165 double sum = 0;
166 for (int i = 0; i < 1000; i++) {
167 double r = Math.random();
168 double x = Math.pow(3, r);
169 sum += x - r;
170 }
171 break;
172 }
173 case BLOCKED: {
174 // signal main thread.
175 thrsync.signal();
176 System.out.println(" myThread is going to block.");
177 synchronized (globalLock) {
178 // finish blocking
179 state = RUNNABLE;
180 }
181 break;
182 }
183 case WAITING: {
184 synchronized (globalLock) {
185 // signal main thread.
186 thrsync.signal();
187 System.out.println(" myThread is going to wait.");
188 try {
189 globalLock.wait();
190 } catch (InterruptedException e) {
191 // ignore
192 }
193 }
194 break;
195 }
196 case TIMED_WAITING: {
197 synchronized (globalLock) {
198 // signal main thread.
199 thrsync.signal();
200 System.out.println(" myThread is going to timed wait.");
201 try {
202 globalLock.wait(10000);
203 } catch (InterruptedException e) {
204 // ignore
205 }
206 }
207 break;
208 }
209 case PARKED: {
210 // signal main thread.
211 thrsync.signal();
212 System.out.println(" myThread is going to park.");
213 LockSupport.park();
214 // give a chance for the main thread to block
215 goSleep(10);
216 break;
217 }
218 case TIMED_PARKED: {
219 // signal main thread.
220 thrsync.signal();
221 System.out.println(" myThread is going to timed park.");
222 long deadline = System.currentTimeMillis() + 10000*1000;
223 LockSupport.parkUntil(deadline);
224
225 // give a chance for the main thread to block
226 goSleep(10);
227 break;
228 }
229 case SLEEPING: {
230 // signal main thread.
231 thrsync.signal();
232 System.out.println(" myThread is going to sleep.");
233 try {
234 Thread.sleep(1000000);
235 } catch (InterruptedException e) {
236 // finish sleeping
237 interrupted();
238 }
239 break;
240 }
241 case TERMINATE: {
242 done = true;
243 // signal main thread.
244 thrsync.signal();
245 break;
246 }
247 default:
248 break;
249 }
250 }
251 }
252 public void waitUntilStarted() {
253 // wait for MyThread.
254 thrsync.waitForSignal();
255 goSleep(10);
256 }
257
258 public void goBlocked() {
259 System.out.println("Waiting myThread to go blocked.");
260 setState(BLOCKED);
261 // wait for MyThread to get blocked
262 thrsync.waitForSignal();
263 goSleep(20);
264 }
265
266 public void goWaiting() {
267 System.out.println("Waiting myThread to go waiting.");
268 setState(WAITING);
269 // wait for MyThread to wait on object.
270 thrsync.waitForSignal();
271 goSleep(20);
272 }
273 public void goTimedWaiting() {
274 System.out.println("Waiting myThread to go timed waiting.");
275 setState(TIMED_WAITING);
276 // wait for MyThread timed wait call.
277 thrsync.waitForSignal();
278 goSleep(20);
279 }
280 public void goParked() {
281 System.out.println("Waiting myThread to go parked.");
282 setState(PARKED);
283 // wait for MyThread state change to PARKED.
284 thrsync.waitForSignal();
285 goSleep(20);
286 }
287 public void goTimedParked() {
288 System.out.println("Waiting myThread to go timed parked.");
289 setState(TIMED_PARKED);
290 // wait for MyThread.
291 thrsync.waitForSignal();
292 goSleep(20);
293 }
294
295 public void goSleeping() {
296 System.out.println("Waiting myThread to go sleeping.");
297 setState(SLEEPING);
298 // wait for MyThread.
299 thrsync.waitForSignal();
300 goSleep(20);
301 }
302 public void terminate() {
303 System.out.println("Waiting myThread to terminate.");
304 setState(TERMINATE);
305 // wait for MyThread.
306 thrsync.waitForSignal();
307 goSleep(20);
308 }
309
310 private void setState(int newState) {
311 switch (state) {
312 case BLOCKED:
313 while (state == BLOCKED) {
314 goSleep(20);
315 }
316 state = newState;
317 break;
318 case WAITING:
319 case TIMED_WAITING:
320 state = newState;
321 synchronized (globalLock) {
322 globalLock.notify();
323 }
324 break;
325 case PARKED:
326 case TIMED_PARKED:
327 state = newState;
328 LockSupport.unpark(this);
329 break;
330 case SLEEPING:
331 state = newState;
332 this.interrupt();
333 break;
334 default:
335 state = newState;
336 break;
337 }
338 }
339 }
340
341
342
343 static class ThreadExecutionSynchronizer {
344
345 private boolean waiting;
346 private Semaphore semaphore;
347
348 public ThreadExecutionSynchronizer() {
349 semaphore = new Semaphore(1);
350 waiting = false;
351 }
352
353 // Synchronizes two threads execution points.
354 // Basically any thread could get scheduled to run and
355 // it is not possible to know which thread reaches expected
356 // execution point. So whichever thread reaches a execution
357 // point first wait for the second thread. When the second thread
358 // reaches the expected execution point will wake up
359 // the thread which is waiting here.
360 void stopOrGo() {
361 semaphore.acquireUninterruptibly(); // Thread can get blocked.
362 if (!waiting) {
363 waiting = true;
364 // Wait for second thread to enter this method.
365 while(!semaphore.hasQueuedThreads()) {
366 try {
367 Thread.sleep(20);
368 } catch (InterruptedException xx) {}
369 }
370 semaphore.release();
371 } else {
372 waiting = false;
373 semaphore.release();
374 }
375 }
376
377 // Wrapper function just for code readability.
378 void waitForSignal() {
379 stopOrGo();
380 }
381
382 void signal() {
383 stopOrGo();
384 }
385 }
386}