1 /* 2 * Written by Doug Lea and Martin Buchholz with assistance from 3 * members of JCP JSR-166 Expert Group and released to the public 4 * domain, as explained at 5 * http://creativecommons.org/publicdomain/zero/1.0/ 6 * Other contributors include Andrew Wright, Jeffrey Hayes, 7 * Pat Fisher, Mike Judd. 8 */ 9 10 package jsr166; 11 12 import junit.framework.*; 13 import java.util.concurrent.CountDownLatch; 14 import java.util.concurrent.atomic.AtomicBoolean; 15 import java.util.concurrent.locks.LockSupport; 16 import static java.util.concurrent.TimeUnit.MILLISECONDS; 17 18 public class LockSupportTest extends JSR166TestCase { 19 20 /** 21 * Returns the blocker object used by tests in this file. 22 * Any old object will do; we'll return a convenient one. 23 */ 24 static Object theBlocker() { 25 return LockSupportTest.class; 26 } 27 28 enum ParkMethod { 29 park() { 30 void park() { 31 LockSupport.park(); 32 } 33 void park(long millis) { 34 throw new UnsupportedOperationException(); 35 } 36 }, 37 parkUntil() { 38 void park(long millis) { 39 LockSupport.parkUntil(deadline(millis)); 40 } 41 }, 42 parkNanos() { 43 void park(long millis) { 44 LockSupport.parkNanos(MILLISECONDS.toNanos(millis)); 45 } 46 }, 47 parkBlocker() { 48 void park() { 49 LockSupport.park(theBlocker()); 50 } 51 void park(long millis) { 52 throw new UnsupportedOperationException(); 53 } 54 }, 55 parkUntilBlocker() { 56 void park(long millis) { 57 LockSupport.parkUntil(theBlocker(), deadline(millis)); 58 } 59 }, 60 parkNanosBlocker() { 61 void park(long millis) { 62 LockSupport.parkNanos(theBlocker(), 63 MILLISECONDS.toNanos(millis)); 64 } 65 }; 66 67 void park() { park(2 * LONG_DELAY_MS); } 68 abstract void park(long millis); 69 70 /** Returns a deadline to use with parkUntil. */ 71 long deadline(long millis) { 72 // beware of rounding 73 return System.currentTimeMillis() + millis + 1; 74 } 75 } 76 77 /** 78 * park is released by subsequent unpark 79 */ 80 public void testParkBeforeUnpark_park() { 81 testParkBeforeUnpark(ParkMethod.park); 82 } 83 public void testParkBeforeUnpark_parkNanos() { 84 testParkBeforeUnpark(ParkMethod.parkNanos); 85 } 86 public void testParkBeforeUnpark_parkUntil() { 87 testParkBeforeUnpark(ParkMethod.parkUntil); 88 } 89 public void testParkBeforeUnpark_parkBlocker() { 90 testParkBeforeUnpark(ParkMethod.parkBlocker); 91 } 92 public void testParkBeforeUnpark_parkNanosBlocker() { 93 testParkBeforeUnpark(ParkMethod.parkNanosBlocker); 94 } 95 public void testParkBeforeUnpark_parkUntilBlocker() { 96 testParkBeforeUnpark(ParkMethod.parkUntilBlocker); 97 } 98 public void testParkBeforeUnpark(final ParkMethod parkMethod) { 99 final CountDownLatch pleaseUnpark = new CountDownLatch(1); 100 Thread t = newStartedThread(new CheckedRunnable() { 101 public void realRun() { 102 pleaseUnpark.countDown(); 103 parkMethod.park(); 104 }}); 105 106 await(pleaseUnpark); 107 LockSupport.unpark(t); 108 awaitTermination(t); 109 } 110 111 /** 112 * park is released by preceding unpark 113 */ 114 public void testParkAfterUnpark_park() { 115 testParkAfterUnpark(ParkMethod.park); 116 } 117 public void testParkAfterUnpark_parkNanos() { 118 testParkAfterUnpark(ParkMethod.parkNanos); 119 } 120 public void testParkAfterUnpark_parkUntil() { 121 testParkAfterUnpark(ParkMethod.parkUntil); 122 } 123 public void testParkAfterUnpark_parkBlocker() { 124 testParkAfterUnpark(ParkMethod.parkBlocker); 125 } 126 public void testParkAfterUnpark_parkNanosBlocker() { 127 testParkAfterUnpark(ParkMethod.parkNanosBlocker); 128 } 129 public void testParkAfterUnpark_parkUntilBlocker() { 130 testParkAfterUnpark(ParkMethod.parkUntilBlocker); 131 } 132 public void testParkAfterUnpark(final ParkMethod parkMethod) { 133 final CountDownLatch pleaseUnpark = new CountDownLatch(1); 134 final AtomicBoolean pleasePark = new AtomicBoolean(false); 135 Thread t = newStartedThread(new CheckedRunnable() { 136 public void realRun() { 137 pleaseUnpark.countDown(); 138 while (!pleasePark.get()) 139 Thread.yield(); 140 parkMethod.park(); 141 }}); 142 143 await(pleaseUnpark); 144 LockSupport.unpark(t); 145 pleasePark.set(true); 146 awaitTermination(t); 147 } 148 149 /** 150 * park is released by subsequent interrupt 151 */ 152 public void testParkBeforeInterrupt_park() { 153 testParkBeforeInterrupt(ParkMethod.park); 154 } 155 public void testParkBeforeInterrupt_parkNanos() { 156 testParkBeforeInterrupt(ParkMethod.parkNanos); 157 } 158 public void testParkBeforeInterrupt_parkUntil() { 159 testParkBeforeInterrupt(ParkMethod.parkUntil); 160 } 161 public void testParkBeforeInterrupt_parkBlocker() { 162 testParkBeforeInterrupt(ParkMethod.parkBlocker); 163 } 164 public void testParkBeforeInterrupt_parkNanosBlocker() { 165 testParkBeforeInterrupt(ParkMethod.parkNanosBlocker); 166 } 167 public void testParkBeforeInterrupt_parkUntilBlocker() { 168 testParkBeforeInterrupt(ParkMethod.parkUntilBlocker); 169 } 170 public void testParkBeforeInterrupt(final ParkMethod parkMethod) { 171 final CountDownLatch pleaseInterrupt = new CountDownLatch(1); 172 Thread t = newStartedThread(new CheckedRunnable() { 173 public void realRun() { 174 pleaseInterrupt.countDown(); 175 do { 176 parkMethod.park(); 177 // park may return spuriously 178 } while (! Thread.currentThread().isInterrupted()); 179 }}); 180 181 await(pleaseInterrupt); 182 assertThreadStaysAlive(t); 183 t.interrupt(); 184 awaitTermination(t); 185 } 186 187 /** 188 * park is released by preceding interrupt 189 */ 190 public void testParkAfterInterrupt_park() { 191 testParkAfterInterrupt(ParkMethod.park); 192 } 193 public void testParkAfterInterrupt_parkNanos() { 194 testParkAfterInterrupt(ParkMethod.parkNanos); 195 } 196 public void testParkAfterInterrupt_parkUntil() { 197 testParkAfterInterrupt(ParkMethod.parkUntil); 198 } 199 public void testParkAfterInterrupt_parkBlocker() { 200 testParkAfterInterrupt(ParkMethod.parkBlocker); 201 } 202 public void testParkAfterInterrupt_parkNanosBlocker() { 203 testParkAfterInterrupt(ParkMethod.parkNanosBlocker); 204 } 205 public void testParkAfterInterrupt_parkUntilBlocker() { 206 testParkAfterInterrupt(ParkMethod.parkUntilBlocker); 207 } 208 public void testParkAfterInterrupt(final ParkMethod parkMethod) { 209 final CountDownLatch pleaseInterrupt = new CountDownLatch(1); 210 final AtomicBoolean pleasePark = new AtomicBoolean(false); 211 Thread t = newStartedThread(new CheckedRunnable() { 212 public void realRun() throws Exception { 213 pleaseInterrupt.countDown(); 214 while (!pleasePark.get()) 215 Thread.yield(); 216 assertTrue(Thread.currentThread().isInterrupted()); 217 parkMethod.park(); 218 assertTrue(Thread.currentThread().isInterrupted()); 219 }}); 220 221 await(pleaseInterrupt); 222 t.interrupt(); 223 pleasePark.set(true); 224 awaitTermination(t); 225 } 226 227 /** 228 * timed park times out if not unparked 229 */ 230 public void testParkTimesOut_parkNanos() { 231 testParkTimesOut(ParkMethod.parkNanos); 232 } 233 public void testParkTimesOut_parkUntil() { 234 testParkTimesOut(ParkMethod.parkUntil); 235 } 236 public void testParkTimesOut_parkNanosBlocker() { 237 testParkTimesOut(ParkMethod.parkNanosBlocker); 238 } 239 public void testParkTimesOut_parkUntilBlocker() { 240 testParkTimesOut(ParkMethod.parkUntilBlocker); 241 } 242 public void testParkTimesOut(final ParkMethod parkMethod) { 243 Thread t = newStartedThread(new CheckedRunnable() { 244 public void realRun() { 245 for (;;) { 246 long startTime = System.nanoTime(); 247 parkMethod.park(timeoutMillis()); 248 // park may return spuriously 249 if (millisElapsedSince(startTime) >= timeoutMillis()) 250 return; 251 } 252 }}); 253 254 awaitTermination(t); 255 } 256 257 /** 258 * getBlocker(null) throws NullPointerException 259 */ 260 public void testGetBlockerNull() { 261 try { 262 LockSupport.getBlocker(null); 263 shouldThrow(); 264 } catch (NullPointerException success) {} 265 } 266 267 /** 268 * getBlocker returns the blocker object passed to park 269 */ 270 public void testGetBlocker_parkBlocker() { 271 testGetBlocker(ParkMethod.parkBlocker); 272 } 273 public void testGetBlocker_parkNanosBlocker() { 274 testGetBlocker(ParkMethod.parkNanosBlocker); 275 } 276 public void testGetBlocker_parkUntilBlocker() { 277 testGetBlocker(ParkMethod.parkUntilBlocker); 278 } 279 public void testGetBlocker(final ParkMethod parkMethod) { 280 final CountDownLatch started = new CountDownLatch(1); 281 Thread t = newStartedThread(new CheckedRunnable() { 282 public void realRun() { 283 Thread t = Thread.currentThread(); 284 started.countDown(); 285 do { 286 assertNull(LockSupport.getBlocker(t)); 287 parkMethod.park(); 288 assertNull(LockSupport.getBlocker(t)); 289 // park may return spuriously 290 } while (! Thread.currentThread().isInterrupted()); 291 }}); 292 293 long startTime = System.nanoTime(); 294 await(started); 295 for (;;) { 296 Object x = LockSupport.getBlocker(t); 297 if (x == theBlocker()) { // success 298 t.interrupt(); 299 awaitTermination(t); 300 assertNull(LockSupport.getBlocker(t)); 301 return; 302 } else { 303 assertNull(x); // ok 304 if (millisElapsedSince(startTime) > LONG_DELAY_MS) 305 fail("timed out"); 306 Thread.yield(); 307 } 308 } 309 } 310 311 /** 312 * timed park(0) returns immediately. 313 * 314 * Requires hotspot fix for: 315 * 6763959 java.util.concurrent.locks.LockSupport.parkUntil(0) blocks forever 316 * which is in jdk7-b118 and 6u25. 317 */ 318 public void testPark0_parkNanos() { 319 testPark0(ParkMethod.parkNanos); 320 } 321 public void testPark0_parkUntil() { 322 testPark0(ParkMethod.parkUntil); 323 } 324 public void testPark0_parkNanosBlocker() { 325 testPark0(ParkMethod.parkNanosBlocker); 326 } 327 public void testPark0_parkUntilBlocker() { 328 testPark0(ParkMethod.parkUntilBlocker); 329 } 330 public void testPark0(final ParkMethod parkMethod) { 331 Thread t = newStartedThread(new CheckedRunnable() { 332 public void realRun() { 333 parkMethod.park(0L); 334 }}); 335 336 awaitTermination(t); 337 } 338 339 /** 340 * timed park(Long.MIN_VALUE) returns immediately. 341 */ 342 public void testParkNeg_parkNanos() { 343 testParkNeg(ParkMethod.parkNanos); 344 } 345 public void testParkNeg_parkUntil() { 346 testParkNeg(ParkMethod.parkUntil); 347 } 348 public void testParkNeg_parkNanosBlocker() { 349 testParkNeg(ParkMethod.parkNanosBlocker); 350 } 351 public void testParkNeg_parkUntilBlocker() { 352 testParkNeg(ParkMethod.parkUntilBlocker); 353 } 354 public void testParkNeg(final ParkMethod parkMethod) { 355 Thread t = newStartedThread(new CheckedRunnable() { 356 public void realRun() { 357 parkMethod.park(Long.MIN_VALUE); 358 }}); 359 360 awaitTermination(t); 361 } 362 } 363