25 * @test |
25 * @test |
26 * @bug 4530538 |
26 * @bug 4530538 |
27 * @summary Basic unit test of the synchronization statistics support: |
27 * @summary Basic unit test of the synchronization statistics support: |
28 * |
28 * |
29 * @author Mandy Chung |
29 * @author Mandy Chung |
30 * |
30 * @author Jaroslav Bachorik |
31 * @ignore 6309226 |
31 * |
32 * @build Semaphore |
|
33 * @run main/othervm SynchronizationStatistics |
32 * @run main/othervm SynchronizationStatistics |
34 */ |
33 */ |
35 |
34 |
36 import java.lang.management.*; |
35 import java.lang.management.*; |
|
36 import java.util.concurrent.Phaser; |
37 |
37 |
38 public class SynchronizationStatistics { |
38 public class SynchronizationStatistics { |
39 private static ThreadMXBean mbean = ManagementFactory.getThreadMXBean(); |
39 private static class LockerThread extends Thread { |
40 |
40 public LockerThread(Runnable r) { |
41 private static boolean blockedTimeCheck = |
41 super(r, "LockerThread"); |
|
42 } |
|
43 } |
|
44 |
|
45 private static final ThreadMXBean mbean = ManagementFactory.getThreadMXBean(); |
|
46 |
|
47 private static final boolean blockedTimeCheck = |
42 mbean.isThreadContentionMonitoringSupported(); |
48 mbean.isThreadContentionMonitoringSupported(); |
43 private static boolean trace = false; |
49 |
44 |
|
45 private static Object lockA = new Object(); |
|
46 private static Object lockB = new Object(); |
|
47 private static Object lockC = new Object(); |
|
48 private static Object lockD = new Object(); |
|
49 private static Object waiter = new Object(); |
|
50 private static volatile boolean testFailed = false; |
|
51 |
|
52 private static Object go = new Object(); |
|
53 |
|
54 private static void goSleep(long ms) { |
|
55 try { |
|
56 Thread.sleep(ms); |
|
57 } catch (InterruptedException e) { |
|
58 e.printStackTrace(); |
|
59 System.out.println("Unexpected exception."); |
|
60 testFailed = true; |
|
61 } |
|
62 } |
|
63 |
50 |
64 public static void main(String args[]) throws Exception { |
51 public static void main(String args[]) throws Exception { |
65 if (args.length > 0 && args[0].equals("trace")) { |
|
66 trace = true; |
|
67 } |
|
68 |
|
69 if (blockedTimeCheck) { |
52 if (blockedTimeCheck) { |
70 mbean.setThreadContentionMonitoringEnabled(true); |
53 mbean.setThreadContentionMonitoringEnabled(true); |
71 } |
54 } |
72 |
55 |
73 if (!mbean.isThreadContentionMonitoringEnabled()) { |
56 if (!mbean.isThreadContentionMonitoringEnabled()) { |
74 throw new RuntimeException("TEST FAILED: " + |
57 throw new RuntimeException("TEST FAILED: " + |
75 "Thread Contention Monitoring is not enabled"); |
58 "Thread Contention Monitoring is not enabled"); |
76 } |
59 } |
77 |
60 |
78 Examiner examiner = new Examiner("Examiner"); |
61 testBlockingOnSimpleMonitor(); |
79 BlockedThread blocked = new BlockedThread("BlockedThread"); |
62 testBlockingOnNestedMonitor(); |
80 examiner.setThread(blocked); |
63 testWaitingOnSimpleMonitor(); |
81 |
64 testMultiWaitingOnSimpleMonitor(); |
82 // Start the threads and check them in Blocked and Waiting states |
65 testWaitingOnNestedMonitor(); |
83 examiner.start(); |
|
84 |
|
85 // wait until the examiner acquires all the locks and waiting |
|
86 // for the BlockedThread to start |
|
87 examiner.waitUntilWaiting(); |
|
88 |
|
89 System.out.println("Checking the thread state for the examiner thread " + |
|
90 "is waiting to begin."); |
|
91 |
|
92 // The Examiner should be waiting to be notified by the BlockedThread |
|
93 checkThreadState(examiner, Thread.State.WAITING); |
|
94 |
|
95 System.out.println("Now starting the blocked thread"); |
|
96 blocked.start(); |
|
97 |
|
98 try { |
|
99 examiner.join(); |
|
100 blocked.join(); |
|
101 } catch (InterruptedException e) { |
|
102 e.printStackTrace(); |
|
103 System.out.println("Unexpected exception."); |
|
104 testFailed = true; |
|
105 } |
|
106 |
|
107 if (testFailed) |
|
108 throw new RuntimeException("TEST FAILED."); |
|
109 |
66 |
110 System.out.println("Test passed."); |
67 System.out.println("Test passed."); |
111 } |
68 } |
112 |
69 |
113 private static String INDENT = " "; |
70 private static LockerThread newLockerThread(Runnable r) { |
114 private static void printStack(Thread t, StackTraceElement[] stack) { |
71 LockerThread t = new LockerThread(r); |
115 System.out.println(INDENT + t + |
72 t.setDaemon(true); |
116 " stack: (length = " + stack.length + ")"); |
73 return t; |
117 if (t != null) { |
74 } |
118 for (int j = 0; j < stack.length; j++) { |
75 |
119 System.out.println(INDENT + stack[j]); |
76 private static void waitForThreadState(Thread t, Thread.State state) throws InterruptedException { |
120 } |
77 while (!t.isInterrupted() && t.getState() != state) { |
121 System.out.println(); |
78 Thread.sleep(3); |
122 } |
79 } |
123 } |
80 } |
124 |
81 |
125 private static void checkThreadState(Thread thread, Thread.State s) |
82 /** |
126 throws Exception { |
83 * Tests that blocking on a single monitor properly increases the |
127 |
84 * blocked count at least by 1. Also asserts that the correct lock name is provided. |
128 ThreadInfo ti = mbean.getThreadInfo(thread.getId()); |
85 */ |
129 if (ti.getThreadState() != s) { |
86 private static void testBlockingOnSimpleMonitor() throws Exception { |
130 ThreadInfo info = mbean.getThreadInfo(thread.getId(), |
87 System.out.println("testBlockingOnSimpleMonitor"); |
131 Integer.MAX_VALUE); |
88 final Object lock1 = new Object(); |
132 System.out.println(INDENT + "TEST FAILED:"); |
89 final Phaser p = new Phaser(2); |
133 printStack(thread, info.getStackTrace()); |
90 LockerThread lt = newLockerThread(new Runnable() { |
134 System.out.println(INDENT + "Thread state: " + info.getThreadState()); |
91 @Override |
135 |
92 public void run() { |
136 throw new RuntimeException("TEST FAILED: " + |
93 p.arriveAndAwaitAdvance(); // phase[1] |
137 "Thread state for " + thread + " returns " + ti.getThreadState() + |
94 synchronized(lock1) { |
138 ". Expected to be " + s); |
95 System.out.println("[LockerThread obtained Lock1]"); |
139 } |
96 p.arriveAndAwaitAdvance(); // phase[2] |
140 } |
97 } |
141 |
98 p.arriveAndAwaitAdvance(); // phase[3] |
142 private static void checkThreadState(Thread thread, |
99 } |
143 Thread.State s1, Thread.State s2) |
100 }); |
144 throws Exception { |
101 |
145 |
102 lt.start(); |
146 ThreadInfo ti = mbean.getThreadInfo(thread.getId()); |
103 long tid = lt.getId(); |
147 if (ti.getThreadState() != s1 && ti.getThreadState() != s2) { |
104 ThreadInfo ti = mbean.getThreadInfo(tid); |
148 throw new RuntimeException("TEST FAILED: " + |
105 String lockName = null; |
149 "Thread state for " + thread + " returns " + ti.getThreadState() + |
106 synchronized(lock1) { |
150 ". Expected to be " + s1 + " or " + s2); |
107 p.arriveAndAwaitAdvance(); // phase[1] |
151 } |
108 waitForThreadState(lt, Thread.State.BLOCKED); |
152 } |
109 lockName = mbean.getThreadInfo(tid).getLockName(); |
153 |
110 } |
154 static class StatThread extends Thread { |
111 |
155 private long blockingBaseTime = 0; |
112 p.arriveAndAwaitAdvance(); // phase[2] |
156 private long totalWaitTime = 0; |
113 testBlocked(ti, mbean.getThreadInfo(tid), lockName, lock1); |
157 private long totalBlockedEnterTime = 0; |
114 p.arriveAndDeregister(); // phase[3] |
158 |
115 |
159 StatThread(String name) { |
116 lt.join(); |
160 super(name); |
117 |
161 } |
118 System.out.println("OK"); |
162 |
119 } |
163 void addWaitTime(long ns) { |
120 |
164 totalWaitTime = totalWaitTime + ns; |
121 /** |
165 } |
122 * Tests that blocking on a nested monitor properly increases the |
166 void addBlockedEnterTime(long ns) { |
123 * blocked count at least by 1 - it is not affected by the nesting depth. |
167 totalBlockedEnterTime = totalBlockedEnterTime + ns; |
124 * Also asserts that the correct lock name is provided. |
168 } |
125 */ |
169 void setBlockingBaseTime(long time) { |
126 private static void testBlockingOnNestedMonitor() throws Exception { |
170 blockingBaseTime = time; |
127 System.out.println("testBlockingOnNestedMonitor"); |
171 } |
128 final Object lock1 = new Object(); |
172 |
129 final Object lock2 = new Object(); |
173 long totalBlockedTimeMs() { |
130 |
174 return totalBlockedEnterTime / 1000000; |
131 final Phaser p = new Phaser(2); |
175 } |
132 LockerThread lt = newLockerThread(new Runnable() { |
176 |
133 @Override |
177 long totalBlockedTimeMs(long now) { |
134 public void run() { |
178 long t = totalBlockedEnterTime + (now - blockingBaseTime); |
135 p.arriveAndAwaitAdvance(); // phase[1] |
179 return t / 1000000; |
136 synchronized(lock1) { |
180 } |
137 System.out.println("[LockerThread obtained Lock1]"); |
181 |
138 p.arriveAndAwaitAdvance(); // phase[2] |
182 long totalWaitTimeMs() { |
139 p.arriveAndAwaitAdvance(); // phase[3] |
183 return totalWaitTime / 1000000; |
140 synchronized(lock2) { |
184 } |
141 System.out.println("[LockerThread obtained Lock2]"); |
185 |
142 p.arriveAndAwaitAdvance(); // phase[4] |
186 long totalWaitTimeMs(long now) { |
143 } |
187 long t = totalWaitTime + (now - blockingBaseTime); |
144 p.arriveAndAwaitAdvance(); // phase[5] |
188 return t / 1000000; |
145 } |
189 } |
146 } |
190 } |
147 }); |
191 |
148 |
192 static class BlockedThread extends StatThread { |
149 lt.start(); |
193 private Semaphore handshake = new Semaphore(); |
150 long tid = lt.getId(); |
194 BlockedThread(String name) { |
151 ThreadInfo ti = mbean.getThreadInfo(tid); |
195 super(name); |
152 ThreadInfo ti1 = null; |
196 } |
153 String lockName = null; |
197 void waitUntilBlocked() { |
154 synchronized(lock1) { |
198 handshake.semaP(); |
155 p.arriveAndAwaitAdvance(); // phase[1] |
199 |
156 waitForThreadState(lt, Thread.State.BLOCKED); |
200 // give a chance for the examiner thread to really wait |
157 lockName = mbean.getThreadInfo(tid).getLockName(); |
201 goSleep(20); |
158 } |
202 } |
159 p.arriveAndAwaitAdvance(); // phase[2] |
203 |
160 |
204 void waitUntilWaiting() { |
161 ti1 = mbean.getThreadInfo(tid); |
205 waitUntilBlocked(); |
162 testBlocked(ti, ti1, lockName, lock1); |
206 } |
163 ti = ti1; |
207 |
164 |
208 boolean hasWaitersForBlocked() { |
165 synchronized(lock2) { |
209 return (handshake.getWaiterCount() > 0); |
166 p.arriveAndAwaitAdvance(); // phase [3] |
210 } |
167 waitForThreadState(lt, Thread.State.BLOCKED); |
211 |
168 lockName = mbean.getThreadInfo(tid).getLockName(); |
212 private void notifyWaiter() { |
169 } |
213 // wait until the examiner waits on the semaphore |
170 p.arriveAndAwaitAdvance(); // phase [4] |
214 while (handshake.getWaiterCount() == 0) { |
171 testBlocked(ti, mbean.getThreadInfo(tid), lockName, lock2); |
215 goSleep(20); |
172 p.arriveAndDeregister(); |
216 } |
173 |
217 handshake.semaV(); |
174 lt.join(); |
218 } |
175 |
219 |
176 System.out.println("OK"); |
220 private void waitObj(long ms) { |
177 } |
221 synchronized (waiter) { |
178 |
222 try { |
179 /** |
223 // notify examinerabout to wait on a monitor |
180 * Tests that waiting on a single monitor properly increases the waited |
224 notifyWaiter(); |
181 * count by 1 and the waited time by a positive number. |
225 |
182 */ |
226 long base = System.nanoTime(); |
183 private static void testWaitingOnSimpleMonitor() throws Exception { |
227 setBlockingBaseTime(base); |
184 System.out.println("testWaitingOnSimpleMonitor"); |
228 waiter.wait(ms); |
185 final Object lock1 = new Object(); |
229 long now = System.nanoTime(); |
186 final Phaser p = new Phaser(2); |
230 addWaitTime(now - base); |
187 LockerThread lt = newLockerThread(new Runnable() { |
231 } catch (Exception e) { |
188 @Override |
232 e.printStackTrace(); |
189 public void run() { |
233 System.out.println("Unexpected exception."); |
190 p.arriveAndAwaitAdvance(); // phase[1] |
234 testFailed = true; |
191 synchronized(lock1) { |
235 } |
192 System.out.println("[LockerThread obtained Lock1]"); |
236 } |
193 try { |
237 } |
194 lock1.wait(300); |
238 |
195 } catch (InterruptedException ex) { |
239 private void test() { |
196 // ignore |
240 // notify examiner about to block on lockA |
197 } |
241 notifyWaiter(); |
198 p.arriveAndAwaitAdvance(); // phase[2] |
242 |
199 } |
243 long base = System.nanoTime(); |
200 p.arriveAndAwaitAdvance(); // phase[3] |
244 setBlockingBaseTime(base); |
201 } |
245 synchronized (lockA) { |
202 }); |
246 long now = System.nanoTime(); |
203 |
247 addBlockedEnterTime(now - base); |
204 lt.start(); |
248 |
205 ThreadInfo ti1 = mbean.getThreadInfo(lt.getId()); |
249 A(); // Expected blocked count = 1 |
206 synchronized(lock1) { |
250 } |
207 p.arriveAndAwaitAdvance(); // phase[1] |
251 E(); |
208 waitForThreadState(lt, Thread.State.BLOCKED); |
252 } |
209 } |
253 private void A() { |
210 p.arriveAndAwaitAdvance(); // phase[2] |
254 // notify examiner about to block on lockB |
211 |
255 notifyWaiter(); |
212 ThreadInfo ti2 = mbean.getThreadInfo(lt.getId()); |
256 |
213 p.arriveAndDeregister(); // phase[3] |
257 long base = System.nanoTime(); |
214 |
258 setBlockingBaseTime(base); |
215 lt.join(); |
259 synchronized (lockB) { |
216 |
260 long now = System.nanoTime(); |
217 testWaited(ti1, ti2, 1); |
261 addBlockedEnterTime(now - base); |
218 System.out.println("OK"); |
262 |
219 } |
263 B(); // Expected blocked count = 2 |
220 |
264 } |
221 /** |
265 } |
222 * Tests that waiting multiple times on the same monitor subsequently |
266 private void B() { |
223 * increases the waited count by the number of subsequent calls and the |
267 // notify examiner about to block on lockC |
224 * waited time by a positive number. |
268 notifyWaiter(); |
225 */ |
269 |
226 private static void testMultiWaitingOnSimpleMonitor() throws Exception { |
270 long base = System.nanoTime(); |
227 System.out.println("testWaitingOnMultipleMonitors"); |
271 setBlockingBaseTime(base); |
228 final Object lock1 = new Object(); |
272 synchronized (lockC) { |
229 |
273 long now = System.nanoTime(); |
230 final Phaser p = new Phaser(2); |
274 addBlockedEnterTime(now - base); |
231 LockerThread lt = newLockerThread(new Runnable() { |
275 |
232 @Override |
276 C(); // Expected blocked count = 3 |
233 public void run() { |
277 } |
234 p.arriveAndAwaitAdvance(); // phase[1] |
278 } |
235 synchronized(lock1) { |
279 private void C() { |
236 System.out.println("[LockerThread obtained Lock1]"); |
280 // notify examiner about to block on lockD |
237 for (int i = 0; i < 3; i++) { |
281 notifyWaiter(); |
238 try { |
282 |
239 lock1.wait(300); |
283 long base = System.nanoTime(); |
240 } catch (InterruptedException ex) { |
284 setBlockingBaseTime(base); |
241 // ignore |
285 synchronized (lockD) { |
242 } |
286 long now = System.nanoTime(); |
243 p.arriveAndAwaitAdvance(); // phase[2-4] |
287 addBlockedEnterTime(now - base); |
244 } |
288 |
245 } |
289 D(); // Expected blocked count = 4 |
246 p.arriveAndAwaitAdvance(); // phase[5] |
290 } |
247 } |
291 } |
248 }); |
292 private void D() { |
249 |
293 goSleep(50); |
250 lt.start(); |
294 } |
251 ThreadInfo ti1 = mbean.getThreadInfo(lt.getId()); |
295 private void E() { |
252 synchronized(lock1) { |
296 final int WAIT = 1000; |
253 p.arriveAndAwaitAdvance(); //phase[1] |
297 waitObj(WAIT); |
254 waitForThreadState(lt, Thread.State.BLOCKED); |
298 waitObj(WAIT); |
255 } |
299 waitObj(WAIT); |
256 int phase = p.getPhase(); |
300 } |
257 while ((p.arriveAndAwaitAdvance() - phase) < 3); // phase[2-4] |
301 |
258 |
302 public void run() { |
259 ThreadInfo ti2 = mbean.getThreadInfo(lt.getId()); |
303 test(); |
260 p.arriveAndDeregister(); // phase[5] |
304 } // run() |
261 |
305 } // BlockedThread |
262 lt.join(); |
306 |
263 testWaited(ti1, ti2, 3); |
307 static int blockedCount = 0; |
264 System.out.println("OK"); |
308 static int waitedCount = 0; |
265 } |
309 static class Examiner extends StatThread { |
266 |
310 private BlockedThread blockedThread; |
267 /** |
311 private Semaphore semaphore = new Semaphore(); |
268 * Tests that waiting on monitors places in nested synchronized blocks |
312 |
269 * properly increases the waited count by the number of times the "lock.wait()" |
313 Examiner(String name) { |
270 * was invoked and the waited time by a positive number. |
314 super(name); |
271 */ |
315 } |
272 private static void testWaitingOnNestedMonitor() throws Exception { |
316 |
273 System.out.println("testWaitingOnNestedMonitor"); |
317 public void setThread(BlockedThread thread) { |
274 final Object lock1 = new Object(); |
318 blockedThread = thread; |
275 final Object lock2 = new Object(); |
319 } |
276 final Object lock3 = new Object(); |
320 |
277 |
321 private void blockedTimeRangeCheck(StatThread t, |
278 final Phaser p = new Phaser(2); |
322 long blockedTime, |
279 LockerThread lt = newLockerThread(new Runnable() { |
323 long nowNano) |
280 @Override |
324 throws Exception { |
281 public void run() { |
325 long expected = t.totalBlockedTimeMs(nowNano); |
282 p.arriveAndAwaitAdvance(); // phase[1] |
326 |
283 synchronized(lock1) { |
327 // accept 5% range |
284 System.out.println("[LockerThread obtained Lock1]"); |
328 timeRangeCheck(blockedTime, expected, 5); |
285 try { |
329 } |
286 lock1.wait(300); |
330 private void waitedTimeRangeCheck(StatThread t, |
287 } catch (InterruptedException ex) { |
331 long waitedTime, |
288 // ignore |
332 long nowNano) |
289 } |
333 throws Exception { |
290 |
334 long expected = t.totalWaitTimeMs(nowNano); |
291 p.arriveAndAwaitAdvance(); // phase[2] |
335 |
292 synchronized(lock2) { |
336 // accept 5% range |
293 System.out.println("[LockerThread obtained Lock2]"); |
337 timeRangeCheck(waitedTime, expected, 5); |
294 try { |
338 } |
295 lock2.wait(300); |
339 |
296 } catch (InterruptedException ex) { |
340 private void timeRangeCheck(long time, long expected, int percent) |
297 // ignore |
341 throws Exception { |
298 } |
342 |
299 |
343 double diff = expected - time; |
300 p.arriveAndAwaitAdvance(); // phase[3] |
344 |
301 synchronized(lock3) { |
345 if (trace) { |
302 System.out.println("[LockerThread obtained Lock3]"); |
346 System.out.println(" Time = " + time + |
303 try { |
347 " expected = " + expected + |
304 lock3.wait(300); |
348 ". Diff = " + diff); |
305 } catch (InterruptedException ex) { |
349 |
306 // ignore |
350 } |
|
351 // throw an exception if blockedTime and expectedTime |
|
352 // differs > percent% |
|
353 if (diff < 0) { |
|
354 diff = diff * -1; |
|
355 } |
|
356 |
|
357 long range = (expected * percent) / 100; |
|
358 // minimum range = 2 ms |
|
359 if (range < 2) { |
|
360 range = 2; |
|
361 } |
|
362 if (diff > range) { |
|
363 throw new RuntimeException("TEST FAILED: " + |
|
364 "Time returned = " + time + |
|
365 " expected = " + expected + ". Diff = " + diff); |
|
366 } |
|
367 } |
|
368 private void checkInfo(StatThread t, Thread.State s, Object lock, |
|
369 String lockName, int bcount, int wcount) |
|
370 throws Exception { |
|
371 |
|
372 String action = "ERROR"; |
|
373 if (s == Thread.State.WAITING || s == Thread.State.TIMED_WAITING) { |
|
374 action = "wait on "; |
|
375 } else if (s == Thread.State.BLOCKED) { |
|
376 action = "block on "; |
|
377 } |
|
378 System.out.println(t + " expected to " + action + lockName + |
|
379 " with blocked count = " + bcount + |
|
380 " and waited count = " + wcount); |
|
381 |
|
382 long now = System.nanoTime(); |
|
383 ThreadInfo info = mbean.getThreadInfo(t.getId()); |
|
384 if (info.getThreadState() != s) { |
|
385 printStack(t, info.getStackTrace()); |
|
386 throw new RuntimeException("TEST FAILED: " + |
|
387 "Thread state returned is " + info.getThreadState() + |
|
388 ". Expected to be " + s); |
|
389 } |
|
390 |
|
391 if (info.getLockName() == null || |
|
392 !info.getLockName().equals(lock.toString())) { |
|
393 throw new RuntimeException("TEST FAILED: " + |
|
394 "getLockName() returned " + info.getLockName() + |
|
395 ". Expected to be " + lockName + " - " + lock.toString()); |
|
396 } |
|
397 |
|
398 if (info.getBlockedCount() != bcount) { |
|
399 throw new RuntimeException("TEST FAILED: " + |
|
400 "Blocked Count returned is " + info.getBlockedCount() + |
|
401 ". Expected to be " + bcount); |
|
402 } |
|
403 if (info.getWaitedCount() != wcount) { |
|
404 throw new RuntimeException("TEST FAILED: " + |
|
405 "Waited Count returned is " + info.getWaitedCount() + |
|
406 ". Expected to be " + wcount); |
|
407 } |
|
408 |
|
409 String lockObj = info.getLockName(); |
|
410 if (lockObj == null || !lockObj.equals(lock.toString())) { |
|
411 throw new RuntimeException("TEST FAILED: " + |
|
412 "Object blocked on is " + lockObj + |
|
413 ". Expected to be " + lock.toString()); |
|
414 } |
|
415 |
|
416 if (!blockedTimeCheck) { |
|
417 return; |
|
418 } |
|
419 long blockedTime = info.getBlockedTime(); |
|
420 if (blockedTime < 0) { |
|
421 throw new RuntimeException("TEST FAILED: " + |
|
422 "Blocked time returned is negative = " + blockedTime); |
|
423 } |
|
424 |
|
425 if (s == Thread.State.BLOCKED) { |
|
426 blockedTimeRangeCheck(t, blockedTime, now); |
|
427 } else { |
|
428 timeRangeCheck(blockedTime, t.totalBlockedTimeMs(), 5); |
|
429 } |
|
430 |
|
431 long waitedTime = info.getWaitedTime(); |
|
432 if (waitedTime < 0) { |
|
433 throw new RuntimeException("TEST FAILED: " + |
|
434 "Waited time returned is negative = " + waitedTime); |
|
435 } |
|
436 if (s == Thread.State.WAITING || s == Thread.State.TIMED_WAITING) { |
|
437 waitedTimeRangeCheck(t, waitedTime, now); |
|
438 } else { |
|
439 timeRangeCheck(waitedTime, t.totalWaitTimeMs(), 5); |
|
440 } |
|
441 |
|
442 } |
|
443 |
|
444 private void examine() { |
|
445 try { |
|
446 synchronized (lockD) { |
|
447 synchronized (lockC) { |
|
448 synchronized (lockB) { |
|
449 synchronized (lockA) { |
|
450 // notify main thread to continue |
|
451 semaphore.semaV(); |
|
452 |
|
453 // wait until BlockedThread has started |
|
454 blockedThread.waitUntilBlocked(); |
|
455 |
|
456 blockedCount++; |
|
457 checkInfo(blockedThread, Thread.State.BLOCKED, |
|
458 lockA, "lockA", |
|
459 blockedCount, waitedCount); |
|
460 } |
307 } |
461 |
308 p.arriveAndAwaitAdvance(); // phase[4] |
462 // wait until BlockedThread to block on lockB |
|
463 blockedThread.waitUntilBlocked(); |
|
464 |
|
465 blockedCount++; |
|
466 checkInfo(blockedThread, Thread.State.BLOCKED, |
|
467 lockB, "lockB", |
|
468 blockedCount, waitedCount); |
|
469 } |
309 } |
470 |
310 } |
471 // wait until BlockedThread to block on lockC |
311 } |
472 blockedThread.waitUntilBlocked(); |
312 p.arriveAndAwaitAdvance(); // phase[5] |
473 |
313 } |
474 blockedCount++; |
314 }); |
475 checkInfo(blockedThread, Thread.State.BLOCKED, |
315 |
476 lockC, "lockC", |
316 lt.start(); |
477 blockedCount, waitedCount); |
317 ThreadInfo ti1 = mbean.getThreadInfo(lt.getId()); |
478 } |
318 synchronized(lock1) { |
479 // wait until BlockedThread to block on lockD |
319 p.arriveAndAwaitAdvance(); // phase[1] |
480 blockedThread.waitUntilBlocked(); |
320 waitForThreadState(lt, Thread.State.BLOCKED); |
481 blockedCount++; |
321 } |
482 |
322 |
483 checkInfo(blockedThread, Thread.State.BLOCKED, |
323 synchronized(lock2) { |
484 lockD, "lockD", |
324 p.arriveAndAwaitAdvance(); // phase[2] |
485 blockedCount, waitedCount); |
325 waitForThreadState(lt, Thread.State.BLOCKED); |
486 } |
326 } |
487 |
327 |
488 // wait until BlockedThread about to call E() |
328 synchronized(lock3) { |
489 // BlockedThread will wait on waiter for 3 times |
329 p.arriveAndAwaitAdvance(); // phase[3] |
490 blockedThread.waitUntilWaiting(); |
330 waitForThreadState(lt, Thread.State.BLOCKED); |
491 |
331 } |
492 waitedCount++; |
332 |
493 checkInfo(blockedThread, Thread.State.TIMED_WAITING, |
333 p.arriveAndAwaitAdvance(); // phase[4] |
494 waiter, "waiter", blockedCount, waitedCount); |
334 ThreadInfo ti2 = mbean.getThreadInfo(lt.getId()); |
495 |
335 p.arriveAndDeregister(); // phase[5] |
496 blockedThread.waitUntilWaiting(); |
336 |
497 |
337 lt.join(); |
498 waitedCount++; |
338 testWaited(ti1, ti2, 3); |
499 checkInfo(blockedThread, Thread.State.TIMED_WAITING, |
339 System.out.println("OK"); |
500 waiter, "waiter", blockedCount, waitedCount); |
340 } |
501 |
341 |
502 blockedThread.waitUntilWaiting(); |
342 private static void testWaited(ThreadInfo ti1, ThreadInfo ti2, int waited) throws Error { |
503 |
343 long waitCntDiff = ti2.getWaitedCount() - ti1.getWaitedCount(); |
504 waitedCount++; |
344 long waitTimeDiff = ti2.getWaitedTime() - ti1.getWaitedTime(); |
505 checkInfo(blockedThread, Thread.State.TIMED_WAITING, |
345 if (waitCntDiff < waited) { |
506 waiter, "waiter", blockedCount, waitedCount); |
346 throw new Error("Unexpected diff in waited count. Expecting at least " |
507 |
347 + waited + " , got " + waitCntDiff); |
508 } catch (Exception e) { |
348 } |
509 e.printStackTrace(); |
349 if (waitTimeDiff <= 0) { |
510 System.out.println("Unexpected exception."); |
350 throw new Error("Unexpected diff in waited time. Expecting increasing " + |
511 testFailed = true; |
351 "value, got " + waitTimeDiff + "ms"); |
512 } |
352 } |
513 } |
353 } |
514 |
354 |
515 public void run() { |
355 private static void testBlocked(ThreadInfo ti1, ThreadInfo ti2, |
516 examine(); |
356 String lockName, final Object lock) |
517 } // run() |
357 throws Error { |
518 |
358 long blkCntDiff = ti2.getBlockedCount() - ti1.getBlockedCount(); |
519 public void waitUntilWaiting() { |
359 long blkTimeDiff = ti2.getBlockedTime() - ti1.getBlockedTime(); |
520 semaphore.semaP(); |
360 if (blkCntDiff < 1) { |
521 |
361 throw new Error("Unexpected diff in blocked count. Expecting at least 1, " + |
522 // wait until the examiner is waiting for |
362 "got " + blkCntDiff); |
523 while (!blockedThread.hasWaitersForBlocked()) { |
363 } |
524 goSleep(50); |
364 if (blkTimeDiff < 0) { |
525 } |
365 throw new Error("Unexpected diff in blocked time. Expecting a positive " + |
526 // give a chance for the examiner thread to really wait |
366 "number, got " + blkTimeDiff); |
527 goSleep(20); |
367 } |
528 |
368 if (!lockName.equals(lock.toString())) { |
529 } |
369 throw new Error("Unexpected blocked monitor name. Expecting " + |
530 } // Examiner |
370 lock.toString() + ", got " + |
|
371 lockName); |
|
372 } |
|
373 } |
531 } |
374 } |