1 /* 2 * Copyright (c) 2003, 2006, 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 * @bug 4967283 5080203 27 * @summary Basic unit test of thread states returned by 28 * ThreadMXBean.getThreadInfo.getThreadState(). 29 * It also tests lock information returned by ThreadInfo. 30 * 31 * @author Mandy Chung 32 * 33 * @build ThreadExecutionSynchronizer Utils 34 * @run main ThreadStateTest 35 */ 36 37 import java.lang.management.ManagementFactory; 38 import java.lang.management.ThreadMXBean; 39 import java.lang.management.ThreadInfo; 40 41 import java.util.concurrent.locks.LockSupport; 42 43 public class ThreadStateTest { 44 private static final ThreadMXBean tm = ManagementFactory.getThreadMXBean(); 45 46 static class Lock { 47 private String name; 48 Lock(String name) { 49 this.name = name; 50 } 51 public String toString() { 52 return name; 53 } 54 } 55 private static Lock globalLock = new Lock("my lock"); 56 57 public static void main(String[] argv) { 58 // Force thread state initialization now before the test 59 // verification begins. 60 Thread.currentThread().getState(); 61 62 MyThread myThread = new MyThread("MyThread"); 63 64 // before myThread starts 65 // Utils.checkThreadState(myThread, Thread.State.NEW); 66 67 myThread.start(); 68 myThread.waitUntilStarted(); 69 Utils.checkThreadState(myThread, Thread.State.RUNNABLE); 70 checkLockInfo(myThread, Thread.State.RUNNABLE, null, null); 71 72 myThread.suspend(); 73 Utils.goSleep(10); 74 checkSuspendedThreadState(myThread, Thread.State.RUNNABLE); 75 myThread.resume(); 76 77 synchronized (globalLock) { 78 myThread.goBlocked(); 79 Utils.checkThreadState(myThread, Thread.State.BLOCKED); 80 checkLockInfo(myThread, Thread.State.BLOCKED, 81 globalLock, Thread.currentThread()); 82 } 83 84 myThread.goWaiting(); 85 Utils.checkThreadState(myThread, Thread.State.WAITING); 86 checkLockInfo(myThread, Thread.State.WAITING, 87 globalLock, null); 88 89 myThread.goTimedWaiting(); 90 Utils.checkThreadState(myThread, Thread.State.TIMED_WAITING); 91 checkLockInfo(myThread, Thread.State.TIMED_WAITING, 92 globalLock, null); 93 94 95 96 /* 97 *********** parkUntil seems not working 98 * ignore this park case for now. 99 100 Bug ID : 5062095 101 *********************************************** 102 myThread.goParked(); 103 Utils.checkThreadState(myThread, Thread.State.WAITING); 104 checkLockInfo(myThread, Thread.State.WAITING, null, null); 105 106 myThread.goTimedParked(); 107 Utils.checkThreadState(myThread, Thread.State.TIMED_WAITING); 108 checkLockInfo(myThread, Thread.State.TIMED_WAITING, null, null); 109 110 */ 111 112 myThread.goSleeping(); 113 Utils.checkThreadState(myThread, Thread.State.TIMED_WAITING); 114 checkLockInfo(myThread, Thread.State.TIMED_WAITING, null, null); 115 116 117 myThread.terminate(); 118 // Utils.checkThreadState(myThread, ThreadState.TERMINATED); 119 120 try { 121 myThread.join(); 122 } catch (InterruptedException e) { 123 e.printStackTrace(); 124 System.out.println("TEST FAILED: Unexpected exception."); 125 throw new RuntimeException(e); 126 } 127 System.out.println("Test passed."); 128 } 129 130 private static void checkSuspendedThreadState(Thread t, Thread.State state) { 131 ThreadInfo info = tm.getThreadInfo(t.getId()); 132 if (info == null) { 133 throw new RuntimeException(t.getName() + 134 " expected to have ThreadInfo " + 135 " but got null."); 136 } 137 138 if (info.getThreadState() != state) { 139 throw new RuntimeException(t.getName() + " expected to be in " + 140 state + " state but got " + info.getThreadState()); 141 } 142 143 if (!info.isSuspended()) { 144 throw new RuntimeException(t.getName() + " expected to be suspended " + 145 " but isSuspended() returns " + info.isSuspended()); 146 } 147 Utils.checkThreadState(t, state); 148 } 149 150 private static String getLockName(Object lock) { 151 if (lock == null) return null; 152 153 return lock.getClass().getName() + '@' + 154 Integer.toHexString(System.identityHashCode(lock)); 155 } 156 157 private static void checkLockInfo(Thread t, Thread.State state, Object lock, Thread owner) { 158 ThreadInfo info = tm.getThreadInfo(t.getId()); 159 if (info == null) { 160 throw new RuntimeException(t.getName() + 161 " expected to have ThreadInfo " + 162 " but got null."); 163 } 164 165 if (info.getThreadState() != state) { 166 throw new RuntimeException(t.getName() + " expected to be in " + 167 state + " state but got " + info.getThreadState()); 168 } 169 170 if (lock == null && info.getLockName() != null) { 171 throw new RuntimeException(t.getName() + 172 " expected not to be blocked on any lock" + 173 " but got " + info.getLockName()); 174 } 175 String expectedLockName = getLockName(lock); 176 if (lock != null && info.getLockName() == null) { 177 throw new RuntimeException(t.getName() + 178 " expected to be blocked on lock [" + expectedLockName + 179 "] but got null."); 180 } 181 182 if (lock != null && !expectedLockName.equals(info.getLockName())) { 183 throw new RuntimeException(t.getName() + 184 " expected to be blocked on lock [" + expectedLockName + 185 "] but got [" + info.getLockName() + "]."); 186 } 187 188 if (owner == null && info.getLockOwnerName() != null) { 189 throw new RuntimeException("Lock owner is expected " + 190 " to be null but got " + info.getLockOwnerName()); 191 } 192 193 if (owner != null && info.getLockOwnerName() == null) { 194 throw new RuntimeException("Lock owner is expected to be " + 195 owner.getName() + 196 " but got null."); 197 } 198 if (owner != null && !info.getLockOwnerName().equals(owner.getName())) { 199 throw new RuntimeException("Lock owner is expected to be " + 200 owner.getName() + 201 " but got " + owner.getName()); 202 } 203 if (owner == null && info.getLockOwnerId() != -1) { 204 throw new RuntimeException("Lock owner is expected " + 205 " to be -1 but got " + info.getLockOwnerId()); 206 } 207 208 if (owner != null && info.getLockOwnerId() <= 0) { 209 throw new RuntimeException("Lock owner is expected to be " + 210 owner.getName() + "(id = " + owner.getId() + 211 ") but got " + info.getLockOwnerId()); 212 } 213 if (owner != null && info.getLockOwnerId() != owner.getId()) { 214 throw new RuntimeException("Lock owner is expected to be " + 215 owner.getName() + "(id = " + owner.getId() + 216 ") but got " + info.getLockOwnerId()); 217 } 218 if (info.isSuspended()) { 219 throw new RuntimeException(t.getName() + 220 " isSuspended() returns " + info.isSuspended()); 221 } 222 } 223 224 static class MyThread extends Thread { 225 private ThreadExecutionSynchronizer thrsync = new ThreadExecutionSynchronizer(); 226 227 MyThread(String name) { 228 super(name); 229 } 230 231 private final int RUNNABLE = 0; 232 private final int BLOCKED = 1; 233 private final int WAITING = 2; 234 private final int TIMED_WAITING = 3; 235 private final int PARKED = 4; 236 private final int TIMED_PARKED = 5; 237 private final int SLEEPING = 6; 238 private final int TERMINATE = 7; 239 private int state = RUNNABLE; 240 241 private boolean done = false; 242 public void run() { 243 // Signal main thread to continue. 244 thrsync.signal(); 245 while (!done) { 246 switch (state) { 247 case RUNNABLE: { 248 double sum = 0; 249 for (int i = 0; i < 1000; i++) { 250 double r = Math.random(); 251 double x = Math.pow(3, r); 252 sum += x - r; 253 } 254 break; 255 } 256 case BLOCKED: { 257 // signal main thread. 258 thrsync.signal(); 259 System.out.println(" myThread is going to block."); 260 synchronized (globalLock) { 261 // finish blocking 262 state = RUNNABLE; 263 } 264 break; 265 } 266 case WAITING: { 267 synchronized (globalLock) { 268 // signal main thread. 269 thrsync.signal(); 270 System.out.println(" myThread is going to wait."); 271 try { 272 globalLock.wait(); 273 } catch (InterruptedException e) { 274 // ignore 275 } 276 } 277 break; 278 } 279 case TIMED_WAITING: { 280 synchronized (globalLock) { 281 // signal main thread. 282 thrsync.signal(); 283 System.out.println(" myThread is going to timed wait."); 284 try { 285 globalLock.wait(10000); 286 } catch (InterruptedException e) { 287 // ignore 288 } 289 } 290 break; 291 } 292 case PARKED: { 293 // signal main thread. 294 thrsync.signal(); 295 System.out.println(" myThread is going to park."); 296 LockSupport.park(); 297 // give a chance for the main thread to block 298 System.out.println(" myThread is going to park."); 299 Utils.goSleep(10); 300 break; 301 } 302 case TIMED_PARKED: { 303 // signal main thread. 304 thrsync.signal(); 305 System.out.println(" myThread is going to timed park."); 306 long deadline = System.currentTimeMillis() + 10000*1000; 307 LockSupport.parkUntil(deadline); 308 309 // give a chance for the main thread to block 310 Utils.goSleep(10); 311 break; 312 } 313 case SLEEPING: { 314 // signal main thread. 315 thrsync.signal(); 316 System.out.println(" myThread is going to sleep."); 317 try { 318 Thread.sleep(1000000); 319 } catch (InterruptedException e) { 320 // finish sleeping 321 interrupted(); 322 } 323 break; 324 } 325 case TERMINATE: { 326 done = true; 327 // signal main thread. 328 thrsync.signal(); 329 break; 330 } 331 default: 332 break; 333 } 334 } 335 } 336 public void waitUntilStarted() { 337 // wait for MyThread. 338 thrsync.waitForSignal(); 339 Utils.goSleep(10); 340 } 341 342 public void goBlocked() { 343 System.out.println("Waiting myThread to go blocked."); 344 setState(BLOCKED); 345 // wait for MyThread to get blocked 346 thrsync.waitForSignal(); 347 Utils.goSleep(20); 348 } 349 350 public void goWaiting() { 351 System.out.println("Waiting myThread to go waiting."); 352 setState(WAITING); 353 // wait for MyThread to wait on object. 354 thrsync.waitForSignal(); 355 Utils.goSleep(20); 356 } 357 public void goTimedWaiting() { 358 System.out.println("Waiting myThread to go timed waiting."); 359 setState(TIMED_WAITING); 360 // wait for MyThread timed wait call. 361 thrsync.waitForSignal(); 362 Utils.goSleep(20); 363 } 364 public void goParked() { 365 System.out.println("Waiting myThread to go parked."); 366 setState(PARKED); 367 // wait for MyThread state change to PARKED. 368 thrsync.waitForSignal(); 369 Utils.goSleep(20); 370 } 371 public void goTimedParked() { 372 System.out.println("Waiting myThread to go timed parked."); 373 setState(TIMED_PARKED); 374 // wait for MyThread. 375 thrsync.waitForSignal(); 376 Utils.goSleep(20); 377 } 378 379 public void goSleeping() { 380 System.out.println("Waiting myThread to go sleeping."); 381 setState(SLEEPING); 382 // wait for MyThread. 383 thrsync.waitForSignal(); 384 Utils.goSleep(20); 385 } 386 public void terminate() { 387 System.out.println("Waiting myThread to terminate."); 388 setState(TERMINATE); 389 // wait for MyThread. 390 thrsync.waitForSignal(); 391 Utils.goSleep(20); 392 } 393 394 private void setState(int newState) { 395 switch (state) { 396 case BLOCKED: 397 while (state == BLOCKED) { 398 Utils.goSleep(20); 399 } 400 state = newState; 401 break; 402 case WAITING: 403 case TIMED_WAITING: 404 state = newState; 405 synchronized (globalLock) { 406 globalLock.notify(); 407 } 408 break; 409 case PARKED: 410 case TIMED_PARKED: 411 state = newState; 412 LockSupport.unpark(this); 413 break; 414 case SLEEPING: 415 state = newState; 416 this.interrupt(); 417 break; 418 default: 419 state = newState; 420 break; 421 } 422 } 423 } 424 }