1 /*
   2  * Copyright (c) 2004, 2011, 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     5014783 8022208
  27  * @summary Basic unit test of thread states returned by
  28  *          Thread.getState().
  29  *
  30  * @author  Mandy Chung
  31  *
  32  * @build ThreadStateTest
  33  * @run main ThreadStateTest
  34  */
  35 
  36 import java.util.concurrent.locks.LockSupport;
  37 import java.util.concurrent.Phaser;
  38 
  39 public class ThreadStateTest {
  40     // maximum number of retries when checking for thread state.
  41     private static final int MAX_RETRY = 500;
  42 
  43     private static boolean testFailed = false;
  44 
  45     // used to achieve waiting states
  46     static final Object globalLock = new Object();
  47 
  48     public static void main(String[] argv) {
  49         // Call Thread.getState to force all initialization done
  50         // before test verification begins.
  51         Thread.currentThread().getState();
  52         MyThread myThread = new MyThread("MyThread");
  53         myThread.setDaemon(true);
  54 
  55         // before myThread starts
  56         checkThreadState(myThread, Thread.State.NEW);
  57 
  58         myThread.start();
  59         myThread.waitUntilStarted();
  60         checkThreadState(myThread, Thread.State.RUNNABLE);
  61 
  62         synchronized (globalLock) {
  63             myThread.goBlocked();
  64             checkThreadState(myThread, Thread.State.BLOCKED);
  65         }
  66 
  67         myThread.goWaiting();
  68         checkThreadState(myThread, Thread.State.WAITING);
  69 
  70         myThread.goTimedWaiting();
  71         checkThreadState(myThread, Thread.State.TIMED_WAITING);
  72 
  73 
  74       /*
  75        *********** park and parkUntil seems not working
  76        * ignore this case for now.
  77        * Bug ID 5062095
  78        ***********************************************
  79 
  80         myThread.goParked();
  81         checkThreadState(myThread, Thread.State.WAITING);
  82 
  83         myThread.goTimedParked();
  84         checkThreadState(myThread, Thread.State.TIMED_WAITING);
  85        */
  86 
  87 
  88         myThread.goSleeping();
  89         checkThreadState(myThread, Thread.State.TIMED_WAITING);
  90 
  91         myThread.terminate();
  92         checkThreadState(myThread, Thread.State.TERMINATED);
  93 
  94         try {
  95             myThread.join();
  96         } catch (InterruptedException e) {
  97             e.printStackTrace();
  98             System.out.println("Unexpected exception.");
  99             testFailed = true;
 100         }
 101 
 102         if (testFailed)
 103             throw new RuntimeException("TEST FAILED.");
 104         System.out.println("Test passed.");
 105     }
 106 
 107     private static void checkThreadState(MyThread t, Thread.State expected) {
 108         // wait for the thread to transition to the expected state.
 109         // There is a small window between the thread checking the state
 110         // and the thread actual entering that state.
 111         Thread.State state;
 112         int retryCount=0;
 113         while ((state = t.getState()) != expected && retryCount < MAX_RETRY) {
 114             goSleep(10);
 115             retryCount++;
 116         }
 117 
 118         if (state == null) {
 119             throw new RuntimeException(t.getName() + " expected to have " +
 120                 expected + " but got null.");
 121         }
 122 
 123         if (state != expected) {
 124             throw new RuntimeException(String.format("%s expected in %s state but got %s " +
 125                 "(iterations %d interrupted %d)%n",
 126                 t.getName(), expected, state, t.iterations, t.interrupted));
 127         }
 128     }
 129 
 130     private static void goSleep(long ms) {
 131         try {
 132             Thread.sleep(ms);
 133         } catch (InterruptedException e) {
 134             e.printStackTrace();
 135             System.out.println("Unexpected exception.");
 136             testFailed = true;
 137         }
 138     }
 139 
 140     static class MyThread extends Thread {
 141         // Phaser to sync between the main thread putting
 142         // this thread into various states
 143         private Phaser phaser =  new Phaser(2);
 144 
 145         MyThread(String name) {
 146             super(name);
 147         }
 148 
 149         private final int RUNNABLE = 0;
 150         private final int BLOCKED = 1;
 151         private final int WAITING = 2;
 152         private final int TIMED_WAITING = 3;
 153         private final int PARKED = 4;
 154         private final int TIMED_PARKED = 5;
 155         private final int SLEEPING = 6;
 156         private final int TERMINATE = 7;
 157 
 158         private volatile int state = RUNNABLE;
 159 
 160         private boolean done = false;
 161         volatile int iterations=0;
 162         volatile int interrupted=0;
 163         public void run() {
 164             // Signal main thread to continue.
 165             phaser.arriveAndAwaitAdvance();
 166 
 167             while (!done) {
 168                 iterations++;
 169                 switch (state) {
 170                     case RUNNABLE: {
 171                         double sum = 0;
 172                         for (int i = 0; i < 1000; i++) {
 173                            double r = Math.random();
 174                            double x = Math.pow(3, r);
 175                            sum += x - r;
 176                         }
 177                         break;
 178                     }
 179                     case BLOCKED: {
 180                         // signal main thread.
 181                         phaser.arrive();
 182                         System.out.println("  myThread is going to block.");
 183                         synchronized (globalLock) {
 184                             // finish blocking
 185                             state = RUNNABLE;
 186                         }
 187                         break;
 188                     }
 189                     case WAITING: {
 190                         synchronized (globalLock) {
 191                             // signal main thread.
 192                             phaser.arrive();
 193                             System.out.println("  myThread is going to wait.");
 194                             try {
 195                                 globalLock.wait();
 196                             } catch (InterruptedException e) {
 197                                 // ignore
 198                                 interrupted++;
 199                             }
 200                         }
 201                         break;
 202                     }
 203                     case TIMED_WAITING: {
 204                         synchronized (globalLock) {
 205                             // signal main thread.
 206                             phaser.arrive();
 207                             System.out.println("  myThread is going to timed wait.");
 208                             try {
 209                                 globalLock.wait(10000);
 210                             } catch (InterruptedException e) {
 211                                 // ignore
 212                                 interrupted++;
 213                             }
 214                         }
 215                         break;
 216                     }
 217                     case PARKED: {
 218                         // signal main thread.
 219                         phaser.arrive();
 220                         System.out.println("  myThread is going to park.");
 221                         LockSupport.park();
 222                         // give a chance for the main thread to block
 223                         goSleep(10);
 224                         break;
 225                     }
 226                     case TIMED_PARKED: {
 227                         // signal main thread.
 228                         phaser.arrive();
 229                         System.out.println("  myThread is going to timed park.");
 230                         long deadline = System.currentTimeMillis() + 10000*1000;
 231                         LockSupport.parkUntil(deadline);
 232 
 233                         // give a chance for the main thread to block
 234                         goSleep(10);
 235                         break;
 236                     }
 237                     case SLEEPING: {
 238                         // signal main thread.
 239                         phaser.arrive();
 240                         System.out.println("  myThread is going to sleep.");
 241                         try {
 242                             Thread.sleep(1000000);
 243                         } catch (InterruptedException e) {
 244                             // finish sleeping
 245                         }
 246                         break;
 247                     }
 248                     case TERMINATE: {
 249                         done = true;
 250                         // signal main thread.
 251                         phaser.arrive();
 252                         break;
 253                     }
 254                     default:
 255                         break;
 256                 }
 257             }
 258         }
 259 
 260         public void waitUntilStarted() {
 261             // wait for MyThread.
 262             phaser.arriveAndAwaitAdvance();
 263         }
 264 
 265         public void goBlocked() {
 266             System.out.println("Waiting myThread to go blocked.");
 267             setState(BLOCKED);
 268             // wait for MyThread to get to a point just before being blocked
 269             phaser.arriveAndAwaitAdvance();
 270         }
 271 
 272         public void goWaiting() {
 273             System.out.println("Waiting myThread to go waiting.");
 274             setState(WAITING);
 275             // wait for MyThread to get to just before wait on object.
 276             phaser.arriveAndAwaitAdvance();
 277         }
 278 
 279         public void goTimedWaiting() {
 280             System.out.println("Waiting myThread to go timed waiting.");
 281             setState(TIMED_WAITING);
 282             // wait for MyThread to get to just before timed wait call.
 283             phaser.arriveAndAwaitAdvance();
 284         }
 285 
 286         public void goParked() {
 287             System.out.println("Waiting myThread to go parked.");
 288             setState(PARKED);
 289             // wait for MyThread to get to just before parked.
 290             phaser.arriveAndAwaitAdvance();
 291         }
 292 
 293         public void goTimedParked() {
 294             System.out.println("Waiting myThread to go timed parked.");
 295             setState(TIMED_PARKED);
 296             // wait for MyThread to get to just before timed park.
 297             phaser.arriveAndAwaitAdvance();
 298         }
 299 
 300         public void goSleeping() {
 301             System.out.println("Waiting myThread to go sleeping.");
 302             setState(SLEEPING);
 303             // wait for MyThread to get to just before sleeping
 304             phaser.arriveAndAwaitAdvance();
 305         }
 306 
 307         public void terminate() {
 308             System.out.println("Waiting myThread to terminate.");
 309             setState(TERMINATE);
 310             // wait for MyThread to get to just before terminate
 311             phaser.arriveAndAwaitAdvance();
 312         }
 313 
 314         private void setState(int newState) {
 315             switch (state) {
 316                 case BLOCKED:
 317                     while (state == BLOCKED) {
 318                         goSleep(10);
 319                     }
 320                     state = newState;
 321                     break;
 322                 case WAITING:
 323                 case TIMED_WAITING:
 324                     state = newState;
 325                     synchronized (globalLock) {
 326                         globalLock.notify();
 327                     }
 328                     break;
 329                 case PARKED:
 330                 case TIMED_PARKED:
 331                     state = newState;
 332                     LockSupport.unpark(this);
 333                     break;
 334                 case SLEEPING:
 335                     state = newState;
 336                     this.interrupt();
 337                     break;
 338                 default:
 339                     state = newState;
 340                     break;
 341             }
 342             iterations=0;
 343             interrupted=0;
 344         }
 345     }
 346 }