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