Print this page


Split Close
Expand all
Collapse all
          --- old/test/java/lang/Thread/ThreadStateTest.java
          +++ new/test/java/lang/Thread/ThreadStateTest.java
   1    1  /*
   2      - * Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
        2 + * Copyright (c) 2004, 2011, Oracle and/or its affiliates. All rights reserved.
   3    3   * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4    4   *
   5    5   * This code is free software; you can redistribute it and/or modify it
   6    6   * under the terms of the GNU General Public License version 2 only, as
   7    7   * published by the Free Software Foundation.
   8    8   *
   9    9   * This code is distributed in the hope that it will be useful, but WITHOUT
  10   10   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11   11   * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12   12   * version 2 for more details (a copy is included in the LICENSE file that
↓ open down ↓ 14 lines elided ↑ open up ↑
  27   27   * @summary Basic unit test of thread states returned by
  28   28   *          Thread.getState().
  29   29   *
  30   30   * @author  Mandy Chung
  31   31   *
  32   32   * @build ThreadStateTest
  33   33   * @run main ThreadStateTest
  34   34   */
  35   35  
  36   36  import java.util.concurrent.locks.LockSupport;
  37      -import java.util.concurrent.Semaphore;
       37 +import java.util.concurrent.Phaser;
  38   38  
  39   39  public class ThreadStateTest {
       40 +    // maximum number of retries when checking for thread state.
       41 +    static final int MAX_RETRY = 500;
       42 +    
  40   43      private static boolean testFailed = false;
  41   44  
  42      -    static class Lock {
  43      -        private String name;
  44      -        Lock(String name) {
  45      -            this.name = name;
  46      -        }
  47      -        public String toString() {
  48      -            return name;
  49      -        }
  50      -    }
  51      -    private static Lock globalLock = new Lock("my lock");
       45 +    // used to achieve waiting states
       46 +    static final Object globalLock = new Object();
  52   47  
  53   48      public static void main(String[] argv) {
  54   49          // Call Thread.getState to force all initialization done
  55   50          // before test verification begins.
  56   51          Thread.currentThread().getState();
  57   52          MyThread myThread = new MyThread("MyThread");
  58   53  
  59   54          // before myThread starts
  60   55          checkThreadState(myThread, Thread.State.NEW);
  61   56  
↓ open down ↓ 24 lines elided ↑ open up ↑
  86   81  
  87   82          myThread.goTimedParked();
  88   83          checkThreadState(myThread, Thread.State.TIMED_WAITING);
  89   84         */
  90   85  
  91   86  
  92   87          myThread.goSleeping();
  93   88          checkThreadState(myThread, Thread.State.TIMED_WAITING);
  94   89  
  95   90          myThread.terminate();
  96      -        checkThreadState(myThread, Thread.State.TERMINATED);
  97      -
  98   91          try {
  99   92              myThread.join();
 100   93          } catch (InterruptedException e) {
 101   94              e.printStackTrace();
 102   95              System.out.println("Unexpected exception.");
 103   96              testFailed = true;
 104   97          }
       98 +        checkThreadState(myThread, Thread.State.TERMINATED);
       99 +
      100 +        
 105  101          if (testFailed)
 106  102              throw new RuntimeException("TEST FAILED.");
 107  103          System.out.println("Test passed.");
 108  104      }
 109  105  
 110  106      private static void checkThreadState(Thread t, Thread.State expected) {
 111      -        Thread.State state = t.getState();
      107 +        // wait for the thread to transition to the expected state.
      108 +        // There is a small window between the thread checking the state
      109 +        // and the thread actual entering that state.
      110 +        Thread.State state;
      111 +        int retryCount=0;
      112 +        while ((state = t.getState()) != expected && retryCount < MAX_RETRY) {
      113 +            if (state != Thread.State.RUNNABLE) {
      114 +                throw new RuntimeException("Thread not in expected state yet," +
      115 +                        " but it should at least be RUNNABLE");
      116 +            }
      117 +            goSleep(10);
      118 +            retryCount++;
      119 +        }
      120 +
 112  121          System.out.println("Checking thread state " + state);
 113  122          if (state == null) {
 114  123              throw new RuntimeException(t.getName() + " expected to have " +
 115  124                  expected + " but got null.");
 116  125          }
 117  126  
 118  127          if (state != expected) {
 119  128              throw new RuntimeException(t.getName() + " expected to have " +
 120  129                  expected + " but got " + state);
 121  130          }
 122  131      }
 123  132  
 124      -    private static String getLockName(Object lock) {
 125      -        if (lock == null) return null;
 126      -
 127      -        return lock.getClass().getName() + '@' +
 128      -            Integer.toHexString(System.identityHashCode(lock));
 129      -    }
 130      -
 131  133      private static void goSleep(long ms) {
 132  134          try {
 133  135              Thread.sleep(ms);
 134  136          } catch (InterruptedException e) {
 135  137              e.printStackTrace();
 136  138              System.out.println("Unexpected exception.");
 137  139              testFailed = true;
 138  140          }
 139  141      }
 140  142  
 141  143      static class MyThread extends Thread {
 142      -        private ThreadExecutionSynchronizer thrsync = new ThreadExecutionSynchronizer();
      144 +        // Phaser to sync between the main thread putting
      145 +        // this thread into various states
      146 +        private Phaser phaser =  new Phaser(2);
 143  147  
 144  148          MyThread(String name) {
 145  149              super(name);
 146  150          }
 147  151  
 148  152          private final int RUNNABLE = 0;
 149  153          private final int BLOCKED = 1;
 150  154          private final int WAITING = 2;
 151  155          private final int TIMED_WAITING = 3;
 152  156          private final int PARKED = 4;
 153  157          private final int TIMED_PARKED = 5;
 154  158          private final int SLEEPING = 6;
 155  159          private final int TERMINATE = 7;
 156      -        private int state = RUNNABLE;
      160 +        
      161 +        private volatile int state = RUNNABLE;
 157  162  
 158  163          private boolean done = false;
 159  164          public void run() {
 160  165              // Signal main thread to continue.
 161      -            thrsync.signal();
      166 +            phaser.arriveAndAwaitAdvance();
      167 +            
 162  168              while (!done) {
 163  169                  switch (state) {
 164  170                      case RUNNABLE: {
 165  171                          double sum = 0;
 166  172                          for (int i = 0; i < 1000; i++) {
 167  173                             double r = Math.random();
 168  174                             double x = Math.pow(3, r);
 169  175                             sum += x - r;
 170  176                          }
 171  177                          break;
 172  178                      }
 173  179                      case BLOCKED: {
 174  180                          // signal main thread.
 175      -                        thrsync.signal();
      181 +                        phaser.arrive();
 176  182                          System.out.println("  myThread is going to block.");
 177  183                          synchronized (globalLock) {
 178  184                              // finish blocking
 179  185                              state = RUNNABLE;
 180  186                          }
 181  187                          break;
 182  188                      }
 183  189                      case WAITING: {
 184  190                          synchronized (globalLock) {
 185  191                              // signal main thread.
 186      -                            thrsync.signal();
      192 +                            phaser.arrive();
 187  193                              System.out.println("  myThread is going to wait.");
 188  194                              try {
 189  195                                  globalLock.wait();
 190  196                              } catch (InterruptedException e) {
 191  197                                  // ignore
 192  198                              }
 193  199                          }
 194  200                          break;
 195  201                      }
 196  202                      case TIMED_WAITING: {
 197  203                          synchronized (globalLock) {
 198  204                              // signal main thread.
 199      -                            thrsync.signal();
      205 +                            phaser.arrive();
 200  206                              System.out.println("  myThread is going to timed wait.");
 201  207                              try {
 202  208                                  globalLock.wait(10000);
 203  209                              } catch (InterruptedException e) {
 204  210                                  // ignore
 205  211                              }
 206  212                          }
 207  213                          break;
 208  214                      }
 209  215                      case PARKED: {
 210  216                          // signal main thread.
 211      -                        thrsync.signal();
      217 +                        phaser.arrive();
 212  218                          System.out.println("  myThread is going to park.");
 213  219                          LockSupport.park();
 214  220                          // give a chance for the main thread to block
 215  221                          goSleep(10);
 216  222                          break;
 217  223                      }
 218  224                      case TIMED_PARKED: {
 219  225                          // signal main thread.
 220      -                        thrsync.signal();
      226 +                        phaser.arrive();
 221  227                          System.out.println("  myThread is going to timed park.");
 222  228                          long deadline = System.currentTimeMillis() + 10000*1000;
 223  229                          LockSupport.parkUntil(deadline);
 224  230  
 225  231                          // give a chance for the main thread to block
 226  232                          goSleep(10);
 227  233                          break;
 228  234                      }
 229  235                      case SLEEPING: {
 230  236                          // signal main thread.
 231      -                        thrsync.signal();
      237 +                        phaser.arrive();
 232  238                          System.out.println("  myThread is going to sleep.");
 233  239                          try {
 234  240                              Thread.sleep(1000000);
 235  241                          } catch (InterruptedException e) {
 236  242                              // finish sleeping
 237  243                              interrupted();
 238  244                          }
 239  245                          break;
 240  246                      }
 241  247                      case TERMINATE: {
 242  248                          done = true;
 243      -                        // signal main thread.
 244      -                        thrsync.signal();
 245  249                          break;
 246  250                      }
 247  251                      default:
 248  252                          break;
 249  253                  }
 250  254              }
 251  255          }
      256 +        
 252  257          public void waitUntilStarted() {
 253  258              // wait for MyThread.
 254      -            thrsync.waitForSignal();
 255      -            goSleep(10);
      259 +            phaser.arriveAndAwaitAdvance();
 256  260          }
 257  261  
 258  262          public void goBlocked() {
 259  263              System.out.println("Waiting myThread to go blocked.");
 260  264              setState(BLOCKED);
 261      -            // wait for MyThread to get blocked
 262      -            thrsync.waitForSignal();
 263      -            goSleep(20);
      265 +            // wait for MyThread to get to a point just before being blocked
      266 +            phaser.arriveAndAwaitAdvance();
 264  267          }
 265  268  
 266  269          public void goWaiting() {
 267  270              System.out.println("Waiting myThread to go waiting.");
 268  271              setState(WAITING);
 269      -            // wait for  MyThread to wait on object.
 270      -            thrsync.waitForSignal();
 271      -            goSleep(20);
      272 +            // wait for MyThread to get to just before wait on object.
      273 +            phaser.arriveAndAwaitAdvance();
 272  274          }
      275 +        
 273  276          public void goTimedWaiting() {
 274  277              System.out.println("Waiting myThread to go timed waiting.");
 275  278              setState(TIMED_WAITING);
 276      -            // wait for MyThread timed wait call.
 277      -            thrsync.waitForSignal();
 278      -            goSleep(20);
      279 +            // wait for MyThread to get to just before timed wait call.
      280 +            phaser.arriveAndAwaitAdvance();
 279  281          }
      282 +        
 280  283          public void goParked() {
 281  284              System.out.println("Waiting myThread to go parked.");
 282  285              setState(PARKED);
 283      -            // wait for  MyThread state change to PARKED.
 284      -            thrsync.waitForSignal();
 285      -            goSleep(20);
      286 +            // wait for MyThread to get to just before parked.
      287 +            phaser.arriveAndAwaitAdvance();
 286  288          }
      289 +        
 287  290          public void goTimedParked() {
 288  291              System.out.println("Waiting myThread to go timed parked.");
 289  292              setState(TIMED_PARKED);
 290      -            // wait for  MyThread.
 291      -            thrsync.waitForSignal();
 292      -            goSleep(20);
      293 +            // wait for MyThread to get to just before timed park.
      294 +            phaser.arriveAndAwaitAdvance();
 293  295          }
 294  296  
 295  297          public void goSleeping() {
 296  298              System.out.println("Waiting myThread to go sleeping.");
 297  299              setState(SLEEPING);
 298      -            // wait for  MyThread.
 299      -            thrsync.waitForSignal();
 300      -            goSleep(20);
      300 +            // wait for MyThread to get to just before sleeping
      301 +            phaser.arriveAndAwaitAdvance();
 301  302          }
      303 +        
 302  304          public void terminate() {
 303  305              System.out.println("Waiting myThread to terminate.");
 304  306              setState(TERMINATE);
 305      -            // wait for  MyThread.
 306      -            thrsync.waitForSignal();
 307      -            goSleep(20);
 308  307          }
 309  308  
 310  309          private void setState(int newState) {
 311  310              switch (state) {
 312  311                  case BLOCKED:
 313  312                      while (state == BLOCKED) {
 314  313                          goSleep(20);
 315  314                      }
 316  315                      state = newState;
 317  316                      break;
↓ open down ↓ 12 lines elided ↑ open up ↑
 330  329                  case SLEEPING:
 331  330                      state = newState;
 332  331                      this.interrupt();
 333  332                      break;
 334  333                  default:
 335  334                      state = newState;
 336  335                      break;
 337  336              }
 338  337          }
 339  338      }
 340      -
 341      -
 342      -
 343      -    static class ThreadExecutionSynchronizer {
 344      -
 345      -        private boolean  waiting;
 346      -        private Semaphore semaphore;
 347      -
 348      -        public ThreadExecutionSynchronizer() {
 349      -            semaphore = new Semaphore(1);
 350      -        waiting = false;
 351      -        }
 352      -
 353      -        // Synchronizes two threads execution points.
 354      -        // Basically any thread could get scheduled to run and
 355      -        // it is not possible to know which thread reaches expected
 356      -        // execution point. So whichever thread reaches a execution
 357      -        // point first wait for the second thread. When the second thread
 358      -        // reaches the expected execution point will wake up
 359      -        // the thread which is waiting here.
 360      -        void stopOrGo() {
 361      -        semaphore.acquireUninterruptibly(); // Thread can get blocked.
 362      -        if (!waiting) {
 363      -            waiting = true;
 364      -            // Wait for second thread to enter this method.
 365      -            while(!semaphore.hasQueuedThreads()) {
 366      -                try {
 367      -                    Thread.sleep(20);
 368      -                } catch (InterruptedException xx) {}
 369      -            }
 370      -            semaphore.release();
 371      -        } else {
 372      -            waiting = false;
 373      -            semaphore.release();
 374      -        }
 375      -        }
 376      -
 377      -        // Wrapper function just for code readability.
 378      -        void waitForSignal() {
 379      -        stopOrGo();
 380      -        }
 381      -
 382      -        void signal() {
 383      -        stopOrGo();
 384      -        }
 385      -    }
 386  339  }
    
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX