/* * 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 * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ /* * @test * @bug 5014783 * @summary Basic unit test of thread states returned by * Thread.getState(). * * @author Mandy Chung * * @build ThreadStateTest * @run main ThreadStateTest */ import java.util.concurrent.locks.LockSupport; 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; // 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 // before test verification begins. Thread.currentThread().getState(); MyThread myThread = new MyThread("MyThread"); // before myThread starts checkThreadState(myThread, Thread.State.NEW); myThread.start(); myThread.waitUntilStarted(); checkThreadState(myThread, Thread.State.RUNNABLE); synchronized (globalLock) { myThread.goBlocked(); checkThreadState(myThread, Thread.State.BLOCKED); } myThread.goWaiting(); checkThreadState(myThread, Thread.State.WAITING); myThread.goTimedWaiting(); checkThreadState(myThread, Thread.State.TIMED_WAITING); /* *********** park and parkUntil seems not working * ignore this case for now. * Bug ID 5062095 *********************************************** myThread.goParked(); checkThreadState(myThread, Thread.State.WAITING); myThread.goTimedParked(); checkThreadState(myThread, Thread.State.TIMED_WAITING); */ myThread.goSleeping(); checkThreadState(myThread, Thread.State.TIMED_WAITING); myThread.terminate(); try { myThread.join(); } catch (InterruptedException e) { e.printStackTrace(); System.out.println("Unexpected exception."); testFailed = true; } checkThreadState(myThread, Thread.State.TERMINATED); if (testFailed) throw new RuntimeException("TEST FAILED."); System.out.println("Test passed."); } private static void checkThreadState(Thread t, Thread.State expected) { // 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 " + expected + " but got null."); } if (state != expected) { throw new RuntimeException(t.getName() + " expected to have " + expected + " but got " + state); } } private static void goSleep(long ms) { try { Thread.sleep(ms); } catch (InterruptedException e) { e.printStackTrace(); System.out.println("Unexpected exception."); testFailed = true; } } static class MyThread extends Thread { // Phaser to sync between the main thread putting // this thread into various states private Phaser phaser = new Phaser(2); MyThread(String name) { super(name); } private final int RUNNABLE = 0; private final int BLOCKED = 1; private final int WAITING = 2; private final int TIMED_WAITING = 3; private final int PARKED = 4; private final int TIMED_PARKED = 5; private final int SLEEPING = 6; private final int TERMINATE = 7; private volatile int state = RUNNABLE; private boolean done = false; public void run() { // Signal main thread to continue. phaser.arriveAndAwaitAdvance(); while (!done) { switch (state) { case RUNNABLE: { double sum = 0; for (int i = 0; i < 1000; i++) { double r = Math.random(); double x = Math.pow(3, r); sum += x - r; } break; } case BLOCKED: { // signal main thread. phaser.arrive(); System.out.println(" myThread is going to block."); synchronized (globalLock) { // finish blocking state = RUNNABLE; } break; } case WAITING: { synchronized (globalLock) { // signal main thread. phaser.arrive(); System.out.println(" myThread is going to wait."); try { globalLock.wait(); } catch (InterruptedException e) { // ignore } } break; } case TIMED_WAITING: { synchronized (globalLock) { // signal main thread. phaser.arrive(); System.out.println(" myThread is going to timed wait."); try { globalLock.wait(10000); } catch (InterruptedException e) { // ignore } } break; } case PARKED: { // signal main thread. phaser.arrive(); System.out.println(" myThread is going to park."); LockSupport.park(); // give a chance for the main thread to block goSleep(10); break; } case TIMED_PARKED: { // signal main thread. phaser.arrive(); System.out.println(" myThread is going to timed park."); long deadline = System.currentTimeMillis() + 10000*1000; LockSupport.parkUntil(deadline); // give a chance for the main thread to block goSleep(10); break; } case SLEEPING: { // signal main thread. 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; break; } default: break; } } } public void waitUntilStarted() { // wait for MyThread. phaser.arriveAndAwaitAdvance(); } public void goBlocked() { System.out.println("Waiting myThread to go blocked."); setState(BLOCKED); // 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 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 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 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 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 to get to just before sleeping phaser.arriveAndAwaitAdvance(); } public void terminate() { System.out.println("Waiting myThread to terminate."); setState(TERMINATE); } private void setState(int newState) { switch (state) { case BLOCKED: while (state == BLOCKED) { goSleep(20); } state = newState; break; case WAITING: case TIMED_WAITING: state = newState; synchronized (globalLock) { globalLock.notify(); } break; case PARKED: case TIMED_PARKED: state = newState; LockSupport.unpark(this); break; case SLEEPING: state = newState; this.interrupt(); break; default: state = newState; break; } } } }