1 /* 2 * Copyright (c) 2013, 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 import java.util.concurrent.Phaser; 25 import java.util.concurrent.atomic.AtomicInteger; 26 import java.util.concurrent.locks.LockSupport; 27 28 /** 29 * ThreadStateController allows the caller to tranition to a specific 30 * thread state. 31 */ 32 public class ThreadStateController extends Thread { 33 // used to achieve waiting states 34 private final Object lock; 35 public ThreadStateController(String name, Object lock) { 36 super(name); 37 this.lock = lock; 38 } 39 40 public static void checkThreadState(ThreadStateController t, Thread.State expected) { 41 // maximum number of retries when checking for thread state. 42 final int MAX_RETRY = 500; 43 44 // wait for the thread to transition to the expected state. 45 // There is a small window between the thread checking the state 46 // and the thread actual entering that state. 47 Thread.State state; 48 int retryCount=0; 49 while ((state = t.getState()) != expected && retryCount < MAX_RETRY) { 50 goSleep(10); 51 retryCount++; 52 } 53 54 if (state == null) { 55 throw new RuntimeException(t.getName() + " expected to have " + 56 expected + " but got null."); 57 } 58 59 if (state != expected) { 60 throw new RuntimeException(String.format("%s expected in %s state but got %s " + 61 "(iterations %d interrupted %d)%n", 62 t.getName(), expected, state, t.iterations, t.interrupted)); 63 } 64 } 65 66 private static void goSleep(long ms) { 67 try { 68 Thread.sleep(ms); 69 } catch (InterruptedException e) { 70 throw new RuntimeException(e); 71 } 72 } 73 74 // Phaser to sync between the main thread putting 75 // this thread into various states 76 private Phaser phaser = new Phaser(2); 77 private final int RUNNABLE = 0; 78 private final int BLOCKED = 1; 79 private final int WAITING = 2; 80 private final int TIMED_WAITING = 3; 81 private final int PARKED = 4; 82 private final int TIMED_PARKED = 5; 83 private final int SLEEPING = 6; 84 private final int TERMINATE = 7; 85 86 private volatile int state = RUNNABLE; 87 private boolean done = false; 88 89 // for debugging 90 private AtomicInteger iterations = new AtomicInteger(); 91 private AtomicInteger interrupted = new AtomicInteger(); 92 public void run() { 93 // Signal main thread to continue. 94 phaser.arriveAndAwaitAdvance(); 95 96 while (!done) { 97 iterations.incrementAndGet(); 98 switch (state) { 99 case RUNNABLE: { 100 double sum = 0; 101 for (int i = 0; i < 1000; i++) { 102 double r = Math.random(); 103 double x = Math.pow(3, r); 104 sum += x - r; 105 } 106 break; 107 } 108 case BLOCKED: { 109 // signal main thread. 110 phaser.arrive(); 111 System.out.println(" myThread is going to block."); 112 synchronized (lock) { 113 // finish blocking 114 state = RUNNABLE; 115 } 116 break; 117 } 118 case WAITING: { 119 synchronized (lock) { 120 // signal main thread. 121 phaser.arrive(); 122 System.out.println(" myThread is going to wait."); 123 try { 124 lock.wait(); 125 } catch (InterruptedException e) { 126 // ignore 127 interrupted.incrementAndGet(); 128 } 129 } 130 break; 131 } 132 case TIMED_WAITING: { 133 synchronized (lock) { 134 // signal main thread. 135 phaser.arrive(); 136 System.out.println(" myThread is going to timed wait."); 137 try { 138 lock.wait(10000); 139 } catch (InterruptedException e) { 140 // ignore 141 interrupted.incrementAndGet(); 142 } 143 } 144 break; 145 } 146 case PARKED: { 147 // signal main thread. 148 phaser.arrive(); 149 System.out.println(" myThread is going to park."); 150 LockSupport.park(); 151 // give a chance for the main thread to block 152 goSleep(10); 153 break; 154 } 155 case TIMED_PARKED: { 156 // signal main thread. 157 phaser.arrive(); 158 System.out.println(" myThread is going to timed park."); 159 long deadline = System.currentTimeMillis() + 10000*1000; 160 LockSupport.parkUntil(deadline); 161 162 // give a chance for the main thread to block 163 goSleep(10); 164 break; 165 } 166 case SLEEPING: { 167 // signal main thread. 168 phaser.arrive(); 169 System.out.println(" myThread is going to sleep."); 170 try { 171 Thread.sleep(1000000); 172 } catch (InterruptedException e) { 173 // finish sleeping 174 } 175 break; 176 } 177 case TERMINATE: { 178 done = true; 179 // signal main thread. 180 phaser.arrive(); 181 break; 182 } 183 default: 184 break; 185 } 186 } 187 } 188 189 public void waitUntilStarted() { 190 // wait for MyThread to start. 191 phaser.arriveAndAwaitAdvance(); 192 } 193 194 public void goBlocked() { 195 System.out.println("Waiting myThread to go blocked."); 196 setState(BLOCKED); 197 // wait for MyThread to get to a point just before being blocked 198 phaser.arriveAndAwaitAdvance(); 199 } 200 201 public void goWaiting() { 202 System.out.println("Waiting myThread to go waiting."); 203 setState(WAITING); 204 // wait for MyThread to get to just before wait on object. 205 phaser.arriveAndAwaitAdvance(); 206 } 207 208 public void goTimedWaiting() { 209 System.out.println("Waiting myThread to go timed waiting."); 210 setState(TIMED_WAITING); 211 // wait for MyThread to get to just before timed wait call. 212 phaser.arriveAndAwaitAdvance(); 213 } 214 215 public void goParked() { 216 System.out.println("Waiting myThread to go parked."); 217 setState(PARKED); 218 // wait for MyThread to get to just before parked. 219 phaser.arriveAndAwaitAdvance(); 220 } 221 222 public void goTimedParked() { 223 System.out.println("Waiting myThread to go timed parked."); 224 setState(TIMED_PARKED); 225 // wait for MyThread to get to just before timed park. 226 phaser.arriveAndAwaitAdvance(); 227 } 228 229 public void goSleeping() { 230 System.out.println("Waiting myThread to go sleeping."); 231 setState(SLEEPING); 232 // wait for MyThread to get to just before sleeping 233 phaser.arriveAndAwaitAdvance(); 234 } 235 236 public void terminate() { 237 System.out.println("Waiting myThread to terminate."); 238 setState(TERMINATE); 239 // wait for MyThread to get to just before terminate 240 phaser.arriveAndAwaitAdvance(); 241 } 242 243 private void setState(int newState) { 244 switch (state) { 245 case BLOCKED: 246 while (state == BLOCKED) { 247 goSleep(10); 248 } 249 state = newState; 250 break; 251 case WAITING: 252 case TIMED_WAITING: 253 state = newState; 254 synchronized (lock) { 255 lock.notify(); 256 } 257 break; 258 case PARKED: 259 case TIMED_PARKED: 260 state = newState; 261 LockSupport.unpark(this); 262 break; 263 case SLEEPING: 264 state = newState; 265 this.interrupt(); 266 break; 267 default: 268 state = newState; 269 break; 270 } 271 iterations.set(0); 272 interrupted.set(0); 273 } 274 }