Basic.java revision 12745:f068a4ffddd2
1/* 2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 3 * 4 * This code is free software; you can redistribute it and/or modify it 5 * under the terms of the GNU General Public License version 2 only, as 6 * published by the Free Software Foundation. 7 * 8 * This code is distributed in the hope that it will be useful, but WITHOUT 9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 11 * version 2 for more details (a copy is included in the LICENSE file that 12 * accompanied this code). 13 * 14 * You should have received a copy of the GNU General Public License version 15 * 2 along with this work; if not, write to the Free Software Foundation, 16 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 17 * 18 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 19 * or visit www.oracle.com if you need additional information or have any 20 * questions. 21 */ 22 23/* 24 * This file is available under and governed by the GNU General Public 25 * License version 2 only, as published by the Free Software Foundation. 26 * However, the following notice accompanied the original version of this 27 * file: 28 * 29 * Written by Doug Lea with assistance from members of JCP JSR-166 30 * Expert Group and released to the public domain, as explained at 31 * http://creativecommons.org/publicdomain/zero/1.0/ 32 */ 33 34/* 35 * @test 36 * @bug 8005697 37 * @summary Basic tests for StampedLock 38 * @author Chris Hegarty 39 */ 40 41import java.util.Iterator; 42import java.util.concurrent.Phaser; 43import java.util.concurrent.TimeUnit; 44import static java.util.concurrent.TimeUnit.*; 45import java.util.concurrent.atomic.AtomicInteger; 46import java.util.concurrent.locks.Lock; 47import java.util.concurrent.locks.ReadWriteLock; 48import java.util.concurrent.locks.StampedLock; 49 50public class Basic { 51 52 static void checkResult(Locker l, Class<? extends Throwable> c) { 53 Throwable t = l.thrown(); 54 if (! ((t == null && c == null) || (c != null && c.isInstance(t)))) { 55 fail("Mismatch in thread " + 56 l.getName() + ": " + 57 t + ", " + 58 (c == null ? "<null>" : c.getName())); 59 } 60 61 if (c == null) 62 check(l.stamp() != 0L); // must have acquired the lock 63 else 64 check(l.stamp() == 0L); // must NOT have acquired the lock 65 } 66 67 //---------------------------------------------------------------- 68 // Mechanism to get all test threads into "running" mode. 69 //---------------------------------------------------------------- 70 static void toTheStartingGate(Phaser gate) { 71 try { 72 gate.arriveAndAwaitAdvance(); 73 } catch (Throwable t) { 74 unexpected(t); 75 } 76 } 77 78 abstract static class Locker extends Thread { 79 static AtomicInteger count = new AtomicInteger(1); 80 private volatile Throwable thrown; 81 private volatile long stamp;; 82 protected void thrown(Throwable thrown) { this.thrown = thrown; } 83 public Throwable thrown() { return thrown; } 84 protected void stamp(long stamp) { this.stamp = stamp; } 85 public long stamp() { return stamp; } 86 87 Locker() { 88 this("Locker"); 89 } 90 91 Locker(String name) { 92 this.setName(name + ":" + count.getAndIncrement()); 93 this.setDaemon(true); 94 } 95 } 96 97 abstract static class Reader extends Locker { 98 Reader() { super("Reader"); } 99 Reader(String name) { super(name); } 100 } 101 102 static Reader reader(final StampedLock sl, final Phaser gate) { 103 return new Reader() { public void run() { 104 if (gate != null ) toTheStartingGate(gate); 105 stamp(sl.readLock()); 106 try { 107 check(sl.validate(stamp())); 108 check(sl.isReadLocked()); 109 check(!sl.isWriteLocked()); 110 } finally { sl.unlockRead(stamp()); } }}; 111 } 112 113 static Reader readerView(final StampedLock sl, final Phaser gate) { 114 return new Reader("ReaderView") { public void run() { 115 if (gate != null ) toTheStartingGate(gate); 116 final Lock rl = sl.asReadLock(); 117 rl.lock(); 118 try { 119 stamp(1L); // got the lock 120 check(sl.isReadLocked()); 121 check(!sl.isWriteLocked()); 122 } finally { rl.unlock(); } }}; 123 } 124 125 static Reader reader(StampedLock sl, Phaser gate, boolean view) { 126 return view ? readerView(sl, gate) : reader(sl, gate); 127 } 128 129 static Reader interruptibleReader(final StampedLock sl, 130 final long timeout, 131 final TimeUnit unit, 132 final Phaser gate) { 133 return new Reader("InterruptibleReader") { public void run() { 134 if (gate != null ) toTheStartingGate(gate); 135 try { 136 if (timeout < 0) 137 stamp(sl.readLockInterruptibly()); 138 else 139 stamp(sl.tryReadLock(timeout, unit)); 140 check(sl.validate(stamp())); 141 check(sl.isReadLocked()); 142 check(!sl.isWriteLocked()); 143 } catch (Throwable x) { thrown(x); 144 } finally { if (stamp() != 0L) sl.unlockRead(stamp()); } }}; 145 } 146 147 static Reader interruptibleReaderView(final StampedLock sl, 148 final long timeout, 149 final TimeUnit unit, 150 final Phaser gate) { 151 return new Reader("InterruptibleReaderView") { public void run() { 152 if (gate != null ) toTheStartingGate(gate); 153 final Lock rl = sl.asReadLock(); 154 155 try { 156 if (timeout < 0) 157 rl.lockInterruptibly(); 158 else 159 rl.tryLock(timeout, unit); 160 stamp(1L); // got the lock 161 check(sl.isReadLocked()); 162 check(!sl.isWriteLocked()); 163 } catch (Throwable x) { thrown(x); 164 } finally { if (stamp() != 0L) rl.unlock(); } }}; 165 } 166 167 static Reader interruptibleReader(final StampedLock sl, 168 final long timeout, 169 final TimeUnit unit, 170 final Phaser gate, 171 final boolean view) { 172 return view ? interruptibleReaderView(sl, timeout, unit, gate) 173 : interruptibleReader(sl, timeout, unit, gate); 174 } 175 176 abstract static class Writer extends Locker { 177 Writer() { super("Writer"); } 178 Writer(String name) { super(name); } 179 } 180 181 static Writer writer(final StampedLock sl, final Phaser gate) { 182 return new Writer() { public void run() { 183 if (gate != null ) toTheStartingGate(gate); 184 try { 185 stamp(sl.writeLock()); 186 check(sl.validate(stamp())); 187 check(!sl.isReadLocked()); 188 check(sl.isWriteLocked()); 189 } finally { sl.unlockWrite(stamp()); } }}; 190 } 191 192 static Writer writerView(final StampedLock sl, final Phaser gate) { 193 return new Writer("WriterView") { public void run() { 194 if (gate != null ) toTheStartingGate(gate); 195 Lock wl = sl.asWriteLock(); 196 wl.lock(); 197 try { 198 stamp(1L); // got the lock 199 check(!sl.isReadLocked()); 200 check(sl.isWriteLocked()); 201 } finally { wl.unlock(); } }}; 202 } 203 204 static Writer writer(StampedLock sl, Phaser gate, boolean view) { 205 return view ? writerView(sl, gate) : writer(sl, gate); 206 } 207 208 static Writer interruptibleWriter(final StampedLock sl, 209 final long timeout, 210 final TimeUnit unit, 211 final Phaser gate) { 212 return new Writer("InterruptibleWriter") { public void run() { 213 if (gate != null ) toTheStartingGate(gate); 214 try { 215 if (timeout < 0) 216 stamp(sl.writeLockInterruptibly()); 217 else 218 stamp(sl.tryWriteLock(timeout, unit)); 219 check(sl.validate(stamp())); 220 check(!sl.isReadLocked()); 221 check(sl.isWriteLocked()); 222 } catch (Throwable x) { thrown(x); 223 } finally { if (stamp() != 0L) sl.unlockWrite(stamp()); } }}; 224 } 225 226 static Writer interruptibleWriterView(final StampedLock sl, 227 final long timeout, 228 final TimeUnit unit, 229 final Phaser gate) { 230 return new Writer("InterruptibleWriterView") { public void run() { 231 if (gate != null ) toTheStartingGate(gate); 232 Lock wl = sl.asWriteLock(); 233 try { 234 if (timeout < 0) 235 wl.lockInterruptibly(); 236 else 237 wl.tryLock(timeout, unit); 238 stamp(1L); // got the lock 239 check(!sl.isReadLocked()); 240 check(sl.isWriteLocked()); 241 } catch (Throwable x) { thrown(x); 242 } finally { if (stamp() != 0L) wl.unlock(); } }}; 243 } 244 245 static Writer interruptibleWriter(final StampedLock sl, 246 final long timeout, 247 final TimeUnit unit, 248 final Phaser gate, 249 final boolean view) { 250 return view ? interruptibleWriterView(sl, timeout, unit, gate) 251 : interruptibleWriter(sl, timeout, unit, gate); 252 } 253 254 // Returns an infinite lazy list of all possible reader combinations. 255 static Iterator<Reader> readerIterator(final StampedLock sl, 256 final Phaser gate) { 257 return new Iterator<Reader>() { 258 int i = 0; 259 boolean view = false; 260 public boolean hasNext() { return true; } 261 public Reader next() { 262 switch ((i++)&7) { 263 case 1: case 4: case 7: 264 return reader(sl, gate, view ^= true); 265 case 2: case 5: 266 return interruptibleReader(sl, -1, SECONDS, gate, view ^= true); 267 default: 268 return interruptibleReader(sl, 30, SECONDS, gate, view ^= true); }} 269 public void remove() {throw new UnsupportedOperationException();}}; 270 } 271 272 // Returns an infinite lazy list of all possible writer combinations. 273 static Iterator<Writer> writerIterator(final StampedLock sl, 274 final Phaser gate) { 275 return new Iterator<Writer>() { 276 int i = 0; 277 boolean view = false; 278 public boolean hasNext() { return true; } 279 public Writer next() { 280 switch ((i++)&7) { 281 case 1: case 4: case 7: 282 return writer(sl, gate, view ^= true); 283 case 2: case 5: 284 return interruptibleWriter(sl, -1, SECONDS, gate, view ^= true); 285 default: 286 return interruptibleWriter(sl, 30, SECONDS, gate, view ^= true); }} 287 public void remove() {throw new UnsupportedOperationException();}}; 288 } 289 290 private static void realMain(String[] args) throws Throwable { 291 292 Thread.currentThread().setName("mainThread"); 293 294 //---------------------------------------------------------------- 295 // Some basic sanity 296 //---------------------------------------------------------------- 297 try { 298 final StampedLock sl = new StampedLock(); 299 check(!sl.isReadLocked()); 300 check(!sl.isWriteLocked()); 301 long stamp = sl.tryOptimisticRead(); 302 check(stamp != 0L); 303 check(sl.validate(stamp)); 304 check(!sl.validate(0)); 305 306 stamp = sl.writeLock(); 307 try { 308 check(sl.validate(stamp)); 309 check(!sl.isReadLocked()); 310 check(sl.isWriteLocked()); 311 check(sl.tryReadLock() == 0L); 312 check(sl.tryReadLock(100, MILLISECONDS) == 0L); 313 check(sl.tryOptimisticRead() == 0L); 314 check(sl.tryWriteLock() == 0L); 315 check(sl.tryWriteLock(100, MILLISECONDS) == 0L); 316 check(!sl.tryUnlockRead()); 317 check(sl.tryConvertToWriteLock(stamp) == stamp); 318 try { 319 sl.unlockRead(stamp); 320 fail("Expected unlockRead to throw when not holding read lock"); 321 } catch (IllegalMonitorStateException x) { 322 pass(); 323 } 324 check(sl.validate(stamp)); 325 } finally { 326 sl.unlockWrite(stamp); 327 } 328 check(!sl.isWriteLocked()); 329 330 stamp = sl.readLock(); 331 try { 332 check(sl.validate(stamp)); 333 check(sl.isReadLocked()); 334 check(!sl.isWriteLocked()); 335 check(sl.tryOptimisticRead() != 0L); 336 check(sl.tryWriteLock() == 0L); 337 check(sl.tryWriteLock(100, MILLISECONDS) == 0L); 338 check(!sl.tryUnlockWrite()); 339 check(sl.tryConvertToReadLock(stamp) == stamp); 340 try { 341 sl.unlockWrite(stamp); 342 fail("Expected unlockWrite to throw when not holding read lock"); 343 } catch (IllegalMonitorStateException x) { 344 pass(); 345 } 346 check(sl.validate(stamp)); 347 } finally { 348 sl.unlockRead(stamp); 349 } 350 check(!sl.isReadLocked()); 351 352 stamp = sl.tryReadLock(100, MILLISECONDS); 353 try { 354 check(stamp != 0L); 355 } finally { 356 sl.unlockRead(stamp); 357 } 358 } catch (Throwable t) { unexpected(t); } 359 360 //---------------------------------------------------------------- 361 // Multiple writers single reader 362 //---------------------------------------------------------------- 363 try { 364 StampedLock sl = new StampedLock(); 365 Phaser gate = new Phaser(102); 366 Iterator<Writer> writers = writerIterator(sl, gate); 367 Iterator<Reader> readers = readerIterator(sl, gate); 368 for (int i = 0; i < 10; i++) { 369 check(!sl.isReadLocked()); 370 check(!sl.isWriteLocked()); 371 check(!sl.tryUnlockRead()); 372 check(!sl.tryUnlockWrite()); 373 check(sl.tryOptimisticRead() != 0L); 374 Locker[] wThreads = new Locker[100];; 375 for (int j=0; j<100; j++) 376 wThreads[j] = writers.next(); 377 for (int j=0; j<100; j++) 378 wThreads[j].start(); 379 Reader reader = readers.next(); reader.start(); 380 toTheStartingGate(gate); 381 reader.join(); 382 for (int j=0; j<100; j++) 383 wThreads[j].join(); 384 for (int j=0; j<100; j++) 385 checkResult(wThreads[j], null); 386 checkResult(reader, null); 387 } 388 } catch (Throwable t) { unexpected(t); } 389 390 //---------------------------------------------------------------- 391 // Multiple readers single writer 392 //---------------------------------------------------------------- 393 try { 394 StampedLock sl = new StampedLock(); 395 Phaser gate = new Phaser(102); 396 Iterator<Writer> writers = writerIterator(sl, gate); 397 Iterator<Reader> readers = readerIterator(sl, gate); 398 for (int i = 0; i < 10; i++) { 399 check(!sl.isReadLocked()); 400 check(!sl.isWriteLocked()); 401 check(!sl.tryUnlockRead()); 402 check(!sl.tryUnlockWrite()); 403 check(sl.tryOptimisticRead() != 0L); 404 Locker[] rThreads = new Locker[100];; 405 for (int j=0; j<100; j++) 406 rThreads[j] = readers.next(); 407 for (int j=0; j<100; j++) 408 rThreads[j].start(); 409 Writer writer = writers.next(); writer.start(); 410 toTheStartingGate(gate); 411 writer.join(); 412 for (int j=0; j<100; j++) 413 rThreads[j].join(); 414 for (int j=0; j<100; j++) 415 checkResult(rThreads[j], null); 416 checkResult(writer, null); 417 } 418 } catch (Throwable t) { unexpected(t); } 419 420 //---------------------------------------------------------------- 421 // thread interrupted 422 //---------------------------------------------------------------- 423 try { 424 boolean view = false; 425 StampedLock sl = new StampedLock(); 426 for (long timeout : new long[] { -1L, 30L, -1L, 30L }) { 427 long stamp = sl.writeLock(); 428 try { 429 Reader r = interruptibleReader(sl, timeout, SECONDS, null, view); 430 r.start(); 431 // allow r to block 432 Thread.sleep(2000); 433 r.interrupt(); 434 r.join(); 435 checkResult(r, InterruptedException.class); 436 } finally { 437 sl.unlockWrite(stamp); 438 } 439 stamp = sl.readLock(); 440 try { 441 Writer w = interruptibleWriter(sl, timeout, SECONDS, null, view); 442 w.start(); 443 // allow w to block 444 Thread.sleep(2000); 445 w.interrupt(); 446 w.join(); 447 checkResult(w, InterruptedException.class); 448 } finally { 449 sl.unlockRead(stamp); 450 } 451 check(!sl.isReadLocked()); 452 check(!sl.isWriteLocked()); 453 check(!sl.tryUnlockRead()); 454 check(!sl.tryUnlockWrite()); 455 check(sl.tryOptimisticRead() != 0L); 456 if (timeout == 30L) 457 view = true; 458 } 459 } catch (Throwable t) { unexpected(t); } 460 461 //---------------------------------------------------------------- 462 // timeout 463 //---------------------------------------------------------------- 464 try { 465 StampedLock sl = new StampedLock(); 466 for (long timeout : new long[] { 0L, 5L }) { 467 long stamp = sl.writeLock(); 468 try { 469 check(sl.tryReadLock(timeout, SECONDS) == 0L); 470 } finally { 471 sl.unlockWrite(stamp); 472 } 473 stamp = sl.readLock(); 474 try { 475 check(sl.tryWriteLock(timeout, SECONDS) == 0L); 476 } finally { 477 sl.unlockRead(stamp); 478 } 479 check(!sl.isReadLocked()); 480 check(!sl.isWriteLocked()); 481 check(!sl.tryUnlockRead()); 482 check(!sl.tryUnlockWrite()); 483 check(sl.tryOptimisticRead() != 0L); 484 } 485 } catch (Throwable t) { unexpected(t); } 486 487 //---------------------------------------------------------------- 488 // optimistic read 489 //---------------------------------------------------------------- 490 try { 491 StampedLock sl = new StampedLock(); 492 Iterator<Writer> writers = writerIterator(sl, null); 493 Iterator<Reader> readers = readerIterator(sl, null); 494 for (int i = 0; i < 10; i++) { 495 check(!sl.isReadLocked()); 496 check(!sl.isWriteLocked()); 497 check(!sl.tryUnlockRead()); 498 check(!sl.tryUnlockWrite()); 499 long stamp = sl.tryOptimisticRead(); 500 check(stamp != 0L); 501 check(sl.tryConvertToOptimisticRead(stamp) == stamp); 502 Reader r = readers.next(); r.start(); 503 r.join(); 504 checkResult(r, null); 505 check(sl.validate(stamp)); 506 check(sl.tryConvertToOptimisticRead(stamp) == stamp); 507 Writer w = writers.next(); w.start(); 508 w.join(); 509 checkResult(w, null); 510 check(sl.validate(stamp) == false); 511 } 512 } catch (Throwable t) { unexpected(t); } 513 514 //---------------------------------------------------------------- 515 // convert 516 //---------------------------------------------------------------- 517 try { 518 StampedLock sl = new StampedLock(); 519 for (int i = 0; i < 2; i++) { 520 check(!sl.isReadLocked()); 521 check(!sl.isWriteLocked()); 522 check(!sl.tryUnlockRead()); 523 check(!sl.tryUnlockWrite()); 524 long stamp = sl.tryOptimisticRead(); 525 check(stamp != 0L); 526 check((stamp = sl.tryConvertToReadLock(stamp)) != 0L); 527 check(sl.validate(stamp)); 528 check(sl.isReadLocked()); 529 check(sl.tryWriteLock() == 0L); 530 check(sl.tryWriteLock(1L, SECONDS) == 0L); 531 check((stamp = sl.tryConvertToWriteLock(stamp)) != 0L); 532 check(sl.validate(stamp)); 533 check(!sl.isReadLocked()); 534 check(sl.isWriteLocked()); 535 check(sl.tryReadLock(1L, SECONDS) == 0L); 536 if (i != 0) { 537 sl.unlockWrite(stamp); 538 continue; 539 } 540 // convert down 541 check((stamp = sl.tryConvertToReadLock(stamp)) != 0L); 542 check(sl.validate(stamp)); 543 check(sl.isReadLocked()); 544 check(!sl.isWriteLocked()); 545 check(sl.tryWriteLock() == 0L); 546 check(sl.tryWriteLock(1L, SECONDS) == 0L); 547 check((stamp = sl.tryConvertToOptimisticRead(stamp)) != 0L); 548 check(sl.validate(stamp)); 549 check(!sl.isReadLocked()); 550 check(!sl.isWriteLocked()); 551 check(sl.validate(stamp)); 552 } 553 } catch (Throwable t) { unexpected(t); } 554 555 //---------------------------------------------------------------- 556 // views 557 //---------------------------------------------------------------- 558 try { 559 StampedLock sl = new StampedLock(); 560 561 Lock rl = sl.asReadLock(); 562 Lock wl = sl.asWriteLock(); 563 for (int i = 0; i < 2; i++) { 564 rl.lock(); 565 try { 566 check(sl.isReadLocked()); 567 check(!sl.isWriteLocked()); 568 check(sl.tryWriteLock() == 0L); 569 check(sl.tryWriteLock(1L, SECONDS) == 0L); 570 } finally { 571 rl.unlock(); 572 } 573 check(!sl.isReadLocked()); 574 check(!sl.isWriteLocked()); 575 576 wl.lock(); 577 try { 578 check(!sl.isReadLocked()); 579 check(sl.isWriteLocked()); 580 check(sl.tryWriteLock() == 0L); 581 check(sl.tryWriteLock(1L, SECONDS) == 0L); 582 } finally { 583 wl.unlock(); 584 } 585 check(!sl.isReadLocked()); 586 check(!sl.isWriteLocked()); 587 588 ReadWriteLock rwl = sl.asReadWriteLock(); 589 rl = rwl.readLock(); 590 wl = rwl.writeLock(); 591 } 592 } catch (Throwable t) { unexpected(t); } 593 } 594 595 //--------------------- Infrastructure --------------------------- 596 static volatile int passed = 0, failed = 0; 597 static void pass() {passed++;} 598 static void fail() {failed++; Thread.dumpStack();} 599 static void fail(String msg) {System.out.println(msg); fail();} 600 static void unexpected(Throwable t) {failed++; t.printStackTrace();} 601 static void check(boolean cond) {if (cond) pass(); else fail();} 602 static void equal(Object x, Object y) { 603 if (x == null ? y == null : x.equals(y)) pass(); 604 else fail(x + " not equal to " + y);} 605 public static void main(String[] args) throws Throwable { 606 try {realMain(args);} catch (Throwable t) {unexpected(t);} 607 System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed); 608 if (failed > 0) throw new AssertionError("Some tests failed");} 609} 610