1 /* 2 * Copyright (c) 2003, 2015, 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 8022208 27 * @summary Basic unit test of thread states returned by 28 * ThreadMXBean.getThreadInfo.getThreadState(). 29 * It also tests lock information returned by ThreadInfo. 30 * @author Mandy Chung 31 * 32 * @library ../../Thread 33 * @library /test/lib 34 * 35 * @build ThreadMXBeanStateTest ThreadStateController 36 * @run main ThreadMXBeanStateTest 37 */ 38 39 import java.lang.management.ManagementFactory; 40 import java.lang.management.ThreadMXBean; 41 import java.lang.management.ThreadInfo; 42 import static java.lang.Thread.State.*; 43 44 public class ThreadMXBeanStateTest { 45 private static final ThreadMXBean tm = ManagementFactory.getThreadMXBean(); 46 47 static class Lock { 48 private final String name; 49 Lock(String name) { 50 this.name = name; 51 } 52 @Override 53 public String toString() { 54 return name; 55 } 56 } 57 58 private static final Lock globalLock = new Lock("my lock"); 59 60 public static void main(String[] argv) throws Exception { 61 // Force thread state initialization now before the test 62 // verification begins. 63 Thread.currentThread().getState(); 64 ThreadStateController thread = new ThreadStateController("StateChanger", globalLock); 65 thread.setDaemon(true); 66 try { 67 // before myThread starts 68 thread.checkThreadState(NEW); 69 70 thread.start(); 71 thread.transitionTo(RUNNABLE); 72 thread.checkThreadState(RUNNABLE); 73 checkLockInfo(thread, RUNNABLE, null, null); 74 75 thread.suspend(); 76 ThreadStateController.pause(10); 77 thread.checkThreadState(RUNNABLE); 78 checkSuspendedThreadState(thread, RUNNABLE); 79 thread.resume(); 80 81 synchronized (globalLock) { 82 thread.transitionTo(BLOCKED); 83 thread.checkThreadState(BLOCKED); 84 checkLockInfo(thread, BLOCKED, 85 globalLock, Thread.currentThread()); 86 } 87 88 thread.transitionTo(WAITING); 89 thread.checkThreadState(WAITING); 90 checkLockInfo(thread, Thread.State.WAITING, 91 globalLock, null); 92 93 thread.transitionTo(TIMED_WAITING); 94 thread.checkThreadState(TIMED_WAITING); 95 checkLockInfo(thread, TIMED_WAITING, 96 globalLock, null); 97 98 99 thread.transitionToPark(true /* timed park */); 100 thread.checkThreadState(TIMED_WAITING); 101 checkLockInfo(thread, TIMED_WAITING, null, null); 102 103 thread.transitionToPark(false /* indefinite park */); 104 thread.checkThreadState(WAITING); 105 checkLockInfo(thread, WAITING, null, null); 106 107 thread.transitionToSleep(); 108 thread.checkThreadState(TIMED_WAITING); 109 checkLockInfo(thread, TIMED_WAITING, null, null); 110 111 thread.transitionTo(TERMINATED); 112 thread.checkThreadState(TERMINATED); 113 } finally { 114 try { 115 System.out.println(thread.getLog()); 116 } catch (InterruptedException e) { 117 e.printStackTrace(); 118 System.out.println("TEST FAILED: Unexpected exception."); 119 throw new RuntimeException(e); 120 } 121 } 122 System.out.println("Test passed."); 123 } 124 125 private static void checkSuspendedThreadState(ThreadStateController t, Thread.State state) { 126 ThreadInfo info = getThreadInfo(t, state); 127 if (info == null) { 128 throw new RuntimeException(t.getName() + 129 " expected to have ThreadInfo " + 130 " but got null."); 131 } 132 133 if (info.getThreadState() != state) { 134 throw new RuntimeException(t.getName() + " expected to be in " + 135 state + " state but got " + info.getThreadState()); 136 } 137 138 if (!info.isSuspended()) { 139 throw new RuntimeException(t.getName() + " expected to be suspended " + 140 " but isSuspended() returns " + info.isSuspended()); 141 } 142 } 143 144 private static String getLockName(Object lock) { 145 if (lock == null) return null; 146 147 return lock.getClass().getName() + '@' + 148 Integer.toHexString(System.identityHashCode(lock)); 149 } 150 151 // maximum number of retries when checking for thread state. 152 private static final int MAX_RETRY = 500; 153 private static ThreadInfo getThreadInfo(ThreadStateController t, Thread.State expected) { 154 // wait for the thread to transition to the expected state. 155 // There is a small window between the thread checking the state 156 // and the thread actual entering that state. 157 int retryCount=0; 158 ThreadInfo info = tm.getThreadInfo(t.getId()); 159 while (info.getThreadState() != expected && retryCount < MAX_RETRY) { 160 ThreadStateController.pause(10); 161 retryCount++; 162 info = tm.getThreadInfo(t.getId()); 163 } 164 return info; 165 } 166 167 private static void checkLockInfo(ThreadStateController t, Thread.State state, 168 Object lock, Thread owner) { 169 ThreadInfo info = getThreadInfo(t, state); 170 if (info == null) { 171 throw new RuntimeException(t.getName() + 172 " expected to have ThreadInfo " + 173 " but got null."); 174 } 175 176 if (info.getThreadState() != state) { 177 throw new RuntimeException(t.getName() + " expected to be in " + 178 state + " state but got " + info.getThreadState()); 179 } 180 181 if (lock == null && info.getLockName() != null) { 182 throw new RuntimeException(t.getName() + 183 " expected not to be blocked on any lock" + 184 " but got " + info.getLockName()); 185 } 186 String expectedLockName = getLockName(lock); 187 if (lock != null && info.getLockName() == null) { 188 throw new RuntimeException(t.getName() + 189 " expected to be blocked on lock [" + expectedLockName + 190 "] but got null."); 191 } 192 193 if (lock != null && !expectedLockName.equals(info.getLockName())) { 194 throw new RuntimeException(t.getName() + 195 " expected to be blocked on lock [" + expectedLockName + 196 "] but got [" + info.getLockName() + "]."); 197 } 198 199 if (owner == null && info.getLockOwnerName() != null) { 200 throw new RuntimeException("Lock owner is expected " + 201 " to be null but got " + info.getLockOwnerName()); 202 } 203 204 if (owner != null && info.getLockOwnerName() == null) { 205 throw new RuntimeException("Lock owner is expected to be " + 206 owner.getName() + 207 " but got null."); 208 } 209 if (owner != null && !info.getLockOwnerName().equals(owner.getName())) { 210 throw new RuntimeException("Lock owner is expected to be " + 211 owner.getName() + 212 " but got " + owner.getName()); 213 } 214 if (owner == null && info.getLockOwnerId() != -1) { 215 throw new RuntimeException("Lock owner is expected " + 216 " to be -1 but got " + info.getLockOwnerId()); 217 } 218 219 if (owner != null && info.getLockOwnerId() <= 0) { 220 throw new RuntimeException("Lock owner is expected to be " + 221 owner.getName() + "(id = " + owner.getId() + 222 ") but got " + info.getLockOwnerId()); 223 } 224 if (owner != null && info.getLockOwnerId() != owner.getId()) { 225 throw new RuntimeException("Lock owner is expected to be " + 226 owner.getName() + "(id = " + owner.getId() + 227 ") but got " + info.getLockOwnerId()); 228 } 229 if (info.isSuspended()) { 230 throw new RuntimeException(t.getName() + 231 " isSuspended() returns " + info.isSuspended()); 232 } 233 } 234 }