7021010: java/lang/Thread/ThreadStateTest.java fails intermittently
authorchegar
Thu, 23 Jun 2011 13:15:14 +0100
changeset 10065 f0dd422f49fa
parent 10064 9f56d9f43ec1
child 10066 bd28f59a9ae2
7021010: java/lang/Thread/ThreadStateTest.java fails intermittently Reviewed-by: dholmes, alanb, mchung
jdk/test/ProblemList.txt
jdk/test/java/lang/Thread/ThreadStateTest.java
--- a/jdk/test/ProblemList.txt	Thu Jun 23 13:00:14 2011 +0100
+++ b/jdk/test/ProblemList.txt	Thu Jun 23 13:15:14 2011 +0100
@@ -207,9 +207,6 @@
 # Times out on solaris sparc -server
 java/lang/ThreadLocal/MemoryLeak.java			 	solaris-all
 
-# Windows X64, RuntimeException: MyThread expected to have RUNNABLE but got WAITING
-java/lang/Thread/ThreadStateTest.java				generic-all
-
 ############################################################################
 
 # jdk_management
--- a/jdk/test/java/lang/Thread/ThreadStateTest.java	Thu Jun 23 13:00:14 2011 +0100
+++ b/jdk/test/java/lang/Thread/ThreadStateTest.java	Thu Jun 23 13:15:14 2011 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2004, 2011, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -34,21 +34,16 @@
  */
 
 import java.util.concurrent.locks.LockSupport;
-import java.util.concurrent.Semaphore;
+import java.util.concurrent.Phaser;
 
 public class ThreadStateTest {
+    // maximum number of retries when checking for thread state.
+    static final int MAX_RETRY = 500;
+
     private static boolean testFailed = false;
 
-    static class Lock {
-        private String name;
-        Lock(String name) {
-            this.name = name;
-        }
-        public String toString() {
-            return name;
-        }
-    }
-    private static Lock globalLock = new Lock("my lock");
+    // used to achieve waiting states
+    static final Object globalLock = new Object();
 
     public static void main(String[] argv) {
         // Call Thread.getState to force all initialization done
@@ -102,13 +97,27 @@
             System.out.println("Unexpected exception.");
             testFailed = true;
         }
+
         if (testFailed)
             throw new RuntimeException("TEST FAILED.");
         System.out.println("Test passed.");
     }
 
     private static void checkThreadState(Thread t, Thread.State expected) {
-        Thread.State state = t.getState();
+        // wait for the thread to transition to the expected state.
+        // There is a small window between the thread checking the state
+        // and the thread actual entering that state.
+        Thread.State state;
+        int retryCount=0;
+        while ((state = t.getState()) != expected && retryCount < MAX_RETRY) {
+            if (state != Thread.State.RUNNABLE) {
+                throw new RuntimeException("Thread not in expected state yet," +
+                        " but it should at least be RUNNABLE");
+            }
+            goSleep(10);
+            retryCount++;
+        }
+
         System.out.println("Checking thread state " + state);
         if (state == null) {
             throw new RuntimeException(t.getName() + " expected to have " +
@@ -121,13 +130,6 @@
         }
     }
 
-    private static String getLockName(Object lock) {
-        if (lock == null) return null;
-
-        return lock.getClass().getName() + '@' +
-            Integer.toHexString(System.identityHashCode(lock));
-    }
-
     private static void goSleep(long ms) {
         try {
             Thread.sleep(ms);
@@ -139,7 +141,9 @@
     }
 
     static class MyThread extends Thread {
-        private ThreadExecutionSynchronizer thrsync = new ThreadExecutionSynchronizer();
+        // Phaser to sync between the main thread putting
+        // this thread into various states
+        private Phaser phaser =  new Phaser(2);
 
         MyThread(String name) {
             super(name);
@@ -153,12 +157,14 @@
         private final int TIMED_PARKED = 5;
         private final int SLEEPING = 6;
         private final int TERMINATE = 7;
-        private int state = RUNNABLE;
+
+        private volatile int state = RUNNABLE;
 
         private boolean done = false;
         public void run() {
             // Signal main thread to continue.
-            thrsync.signal();
+            phaser.arriveAndAwaitAdvance();
+
             while (!done) {
                 switch (state) {
                     case RUNNABLE: {
@@ -172,7 +178,7 @@
                     }
                     case BLOCKED: {
                         // signal main thread.
-                        thrsync.signal();
+                        phaser.arrive();
                         System.out.println("  myThread is going to block.");
                         synchronized (globalLock) {
                             // finish blocking
@@ -183,7 +189,7 @@
                     case WAITING: {
                         synchronized (globalLock) {
                             // signal main thread.
-                            thrsync.signal();
+                            phaser.arrive();
                             System.out.println("  myThread is going to wait.");
                             try {
                                 globalLock.wait();
@@ -196,7 +202,7 @@
                     case TIMED_WAITING: {
                         synchronized (globalLock) {
                             // signal main thread.
-                            thrsync.signal();
+                            phaser.arrive();
                             System.out.println("  myThread is going to timed wait.");
                             try {
                                 globalLock.wait(10000);
@@ -208,7 +214,7 @@
                     }
                     case PARKED: {
                         // signal main thread.
-                        thrsync.signal();
+                        phaser.arrive();
                         System.out.println("  myThread is going to park.");
                         LockSupport.park();
                         // give a chance for the main thread to block
@@ -217,7 +223,7 @@
                     }
                     case TIMED_PARKED: {
                         // signal main thread.
-                        thrsync.signal();
+                        phaser.arrive();
                         System.out.println("  myThread is going to timed park.");
                         long deadline = System.currentTimeMillis() + 10000*1000;
                         LockSupport.parkUntil(deadline);
@@ -228,20 +234,19 @@
                     }
                     case SLEEPING: {
                         // signal main thread.
-                        thrsync.signal();
+                        phaser.arrive();
                         System.out.println("  myThread is going to sleep.");
                         try {
                             Thread.sleep(1000000);
                         } catch (InterruptedException e) {
                             // finish sleeping
-                            interrupted();
                         }
                         break;
                     }
                     case TERMINATE: {
                         done = true;
                         // signal main thread.
-                        thrsync.signal();
+                        phaser.arrive();
                         break;
                     }
                     default:
@@ -249,69 +254,66 @@
                 }
             }
         }
+
         public void waitUntilStarted() {
             // wait for MyThread.
-            thrsync.waitForSignal();
-            goSleep(10);
+            phaser.arriveAndAwaitAdvance();
         }
 
         public void goBlocked() {
             System.out.println("Waiting myThread to go blocked.");
             setState(BLOCKED);
-            // wait for MyThread to get blocked
-            thrsync.waitForSignal();
-            goSleep(20);
+            // wait for MyThread to get to a point just before being blocked
+            phaser.arriveAndAwaitAdvance();
         }
 
         public void goWaiting() {
             System.out.println("Waiting myThread to go waiting.");
             setState(WAITING);
-            // wait for  MyThread to wait on object.
-            thrsync.waitForSignal();
-            goSleep(20);
+            // wait for MyThread to get to just before wait on object.
+            phaser.arriveAndAwaitAdvance();
         }
+
         public void goTimedWaiting() {
             System.out.println("Waiting myThread to go timed waiting.");
             setState(TIMED_WAITING);
-            // wait for MyThread timed wait call.
-            thrsync.waitForSignal();
-            goSleep(20);
+            // wait for MyThread to get to just before timed wait call.
+            phaser.arriveAndAwaitAdvance();
         }
+
         public void goParked() {
             System.out.println("Waiting myThread to go parked.");
             setState(PARKED);
-            // wait for  MyThread state change to PARKED.
-            thrsync.waitForSignal();
-            goSleep(20);
+            // wait for MyThread to get to just before parked.
+            phaser.arriveAndAwaitAdvance();
         }
+
         public void goTimedParked() {
             System.out.println("Waiting myThread to go timed parked.");
             setState(TIMED_PARKED);
-            // wait for  MyThread.
-            thrsync.waitForSignal();
-            goSleep(20);
+            // wait for MyThread to get to just before timed park.
+            phaser.arriveAndAwaitAdvance();
         }
 
         public void goSleeping() {
             System.out.println("Waiting myThread to go sleeping.");
             setState(SLEEPING);
-            // wait for  MyThread.
-            thrsync.waitForSignal();
-            goSleep(20);
+            // wait for MyThread to get to just before sleeping
+            phaser.arriveAndAwaitAdvance();
         }
+
         public void terminate() {
             System.out.println("Waiting myThread to terminate.");
             setState(TERMINATE);
-            // wait for  MyThread.
-            thrsync.waitForSignal();
-            goSleep(20);
+            // wait for MyThread to get to just before terminate
+            phaser.arriveAndAwaitAdvance();
         }
 
         private void setState(int newState) {
             switch (state) {
                 case BLOCKED:
                     while (state == BLOCKED) {
-                        goSleep(20);
+                        goSleep(10);
                     }
                     state = newState;
                     break;
@@ -337,50 +339,4 @@
             }
         }
     }
-
-
-
-    static class ThreadExecutionSynchronizer {
-
-        private boolean  waiting;
-        private Semaphore semaphore;
-
-        public ThreadExecutionSynchronizer() {
-            semaphore = new Semaphore(1);
-        waiting = false;
-        }
-
-        // Synchronizes two threads execution points.
-        // Basically any thread could get scheduled to run and
-        // it is not possible to know which thread reaches expected
-        // execution point. So whichever thread reaches a execution
-        // point first wait for the second thread. When the second thread
-        // reaches the expected execution point will wake up
-        // the thread which is waiting here.
-        void stopOrGo() {
-        semaphore.acquireUninterruptibly(); // Thread can get blocked.
-        if (!waiting) {
-            waiting = true;
-            // Wait for second thread to enter this method.
-            while(!semaphore.hasQueuedThreads()) {
-                try {
-                    Thread.sleep(20);
-                } catch (InterruptedException xx) {}
-            }
-            semaphore.release();
-        } else {
-            waiting = false;
-            semaphore.release();
-        }
-        }
-
-        // Wrapper function just for code readability.
-        void waitForSignal() {
-        stopOrGo();
-        }
-
-        void signal() {
-        stopOrGo();
-        }
-    }
 }