| /* |
| * Copyright (c) 2004, 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.Semaphore; |
| |
| public class ThreadStateTest { |
| 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"); |
| |
| 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(); |
| checkThreadState(myThread, Thread.State.TERMINATED); |
| |
| try { |
| myThread.join(); |
| } catch (InterruptedException e) { |
| e.printStackTrace(); |
| 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(); |
| 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 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); |
| } catch (InterruptedException e) { |
| e.printStackTrace(); |
| System.out.println("Unexpected exception."); |
| testFailed = true; |
| } |
| } |
| |
| static class MyThread extends Thread { |
| private ThreadExecutionSynchronizer thrsync = new ThreadExecutionSynchronizer(); |
| |
| 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 int state = RUNNABLE; |
| |
| private boolean done = false; |
| public void run() { |
| // Signal main thread to continue. |
| thrsync.signal(); |
| 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. |
| thrsync.signal(); |
| System.out.println(" myThread is going to block."); |
| synchronized (globalLock) { |
| // finish blocking |
| state = RUNNABLE; |
| } |
| break; |
| } |
| case WAITING: { |
| synchronized (globalLock) { |
| // signal main thread. |
| thrsync.signal(); |
| System.out.println(" myThread is going to wait."); |
| try { |
| globalLock.wait(); |
| } catch (InterruptedException e) { |
| // ignore |
| } |
| } |
| break; |
| } |
| case TIMED_WAITING: { |
| synchronized (globalLock) { |
| // signal main thread. |
| thrsync.signal(); |
| System.out.println(" myThread is going to timed wait."); |
| try { |
| globalLock.wait(10000); |
| } catch (InterruptedException e) { |
| // ignore |
| } |
| } |
| break; |
| } |
| case PARKED: { |
| // signal main thread. |
| thrsync.signal(); |
| 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. |
| thrsync.signal(); |
| 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. |
| thrsync.signal(); |
| 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(); |
| break; |
| } |
| default: |
| break; |
| } |
| } |
| } |
| public void waitUntilStarted() { |
| // wait for MyThread. |
| thrsync.waitForSignal(); |
| goSleep(10); |
| } |
| |
| public void goBlocked() { |
| System.out.println("Waiting myThread to go blocked."); |
| setState(BLOCKED); |
| // wait for MyThread to get blocked |
| thrsync.waitForSignal(); |
| goSleep(20); |
| } |
| |
| public void goWaiting() { |
| System.out.println("Waiting myThread to go waiting."); |
| setState(WAITING); |
| // wait for MyThread to wait on object. |
| thrsync.waitForSignal(); |
| goSleep(20); |
| } |
| 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); |
| } |
| public void goParked() { |
| System.out.println("Waiting myThread to go parked."); |
| setState(PARKED); |
| // wait for MyThread state change to PARKED. |
| thrsync.waitForSignal(); |
| goSleep(20); |
| } |
| public void goTimedParked() { |
| System.out.println("Waiting myThread to go timed parked."); |
| setState(TIMED_PARKED); |
| // wait for MyThread. |
| thrsync.waitForSignal(); |
| goSleep(20); |
| } |
| |
| public void goSleeping() { |
| System.out.println("Waiting myThread to go sleeping."); |
| setState(SLEEPING); |
| // wait for MyThread. |
| thrsync.waitForSignal(); |
| goSleep(20); |
| } |
| public void terminate() { |
| System.out.println("Waiting myThread to terminate."); |
| setState(TERMINATE); |
| // wait for MyThread. |
| thrsync.waitForSignal(); |
| goSleep(20); |
| } |
| |
| 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; |
| } |
| } |
| } |
| |
| |
| |
| 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(); |
| } |
| } |
| } |