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 4486658 37 * @summary basic safety and liveness of ReentrantLocks, and other locks based on them 38 * @library /test/lib 39 */ 40 41 import static java.util.concurrent.TimeUnit.MILLISECONDS; 42 43 import java.util.concurrent.CyclicBarrier; 44 import java.util.concurrent.ExecutorService; 45 import java.util.concurrent.Executors; 46 import java.util.concurrent.Semaphore; 47 import java.util.concurrent.ThreadLocalRandom; 48 import java.util.concurrent.locks.Lock; 49 import java.util.concurrent.locks.ReentrantLock; 50 import java.util.concurrent.locks.ReentrantReadWriteLock; 51 import jdk.test.lib.Utils; 52 53 public final class CheckedLockLoops { 54 static final long LONG_DELAY_MS = Utils.adjustTimeout(10_000); 55 static ExecutorService pool; 56 57 public static void main(String[] args) throws Exception { 58 final int maxThreads = (args.length > 0) 59 ? Integer.parseInt(args[0]) 60 : 5; 61 int iters = 3000; 62 63 pool = Executors.newCachedThreadPool(); 64 for (int i = 1; i <= maxThreads; i += (i+1) >>> 1) { 65 oneTest(i, iters / i); 66 } 67 pool.shutdown(); 68 if (! pool.awaitTermination(LONG_DELAY_MS, MILLISECONDS)) 69 throw new Error(); 70 pool = null; 71 } 72 73 static void oneTest(int nthreads, int iters) throws Exception { 74 System.out.println("Threads: " + nthreads); 75 int v = ThreadLocalRandom.current().nextInt(); 76 System.out.print("builtin lock "); 77 new BuiltinLockLoop().test(v, nthreads, iters); 78 79 System.out.print("ReentrantLock "); 80 new ReentrantLockLoop().test(v, nthreads, iters); 81 82 System.out.print("Mutex "); 83 new MutexLoop().test(v, nthreads, iters); 84 85 System.out.print("ReentrantWriteLock "); 86 new ReentrantWriteLockLoop().test(v, nthreads, iters); 87 88 System.out.print("ReentrantReadWriteLock"); 89 new ReentrantReadWriteLockLoop().test(v, nthreads, iters); 90 91 System.out.print("Semaphore "); 92 new SemaphoreLoop().test(v, nthreads, iters); 93 94 System.out.print("fair Semaphore "); 95 new FairSemaphoreLoop().test(v, nthreads, iters); 96 97 System.out.print("FairReentrantLock "); 98 new FairReentrantLockLoop().test(v, nthreads, iters); 99 100 System.out.print("FairRWriteLock "); 101 new FairReentrantWriteLockLoop().test(v, nthreads, iters); 102 103 System.out.print("FairRReadWriteLock "); 104 new FairReentrantReadWriteLockLoop().test(v, nthreads, iters); 105 } 106 107 abstract static class LockLoop implements Runnable { 108 int value; 109 int checkValue; 110 int iters; 111 volatile int result; 112 final LoopHelpers.BarrierTimer timer = new LoopHelpers.BarrierTimer(); 113 CyclicBarrier barrier; 114 115 final int setValue(int v) { 116 checkValue = v ^ 0x55555555; 117 value = v; 118 return v; 119 } 120 121 final int getValue() { 122 int v = value; 123 if (checkValue != ~(v ^ 0xAAAAAAAA)) 124 throw new Error("lock protection failure"); 125 return v; 126 } 127 128 final void test(int initialValue, int nthreads, int iters) throws Exception { 129 setValue(initialValue); 130 this.iters = iters; 131 barrier = new CyclicBarrier(nthreads+1, timer); 132 for (int i = 0; i < nthreads; ++i) 133 pool.execute(this); 134 barrier.await(); 135 barrier.await(); 136 long time = timer.getTime(); 137 long tpi = time / (iters * nthreads); 138 System.out.print("\t" + LoopHelpers.rightJustify(tpi) + " ns per update"); 139 // double secs = (double)(time) / 1000000000.0; 140 // System.out.print("\t " + secs + "s run time"); 141 System.out.println(); 142 143 if (result == 0) // avoid overoptimization 144 System.out.println("useless result: " + result); 145 } 146 abstract int loop(int n); 147 public final void run() { 148 try { 149 barrier.await(); 150 result += loop(iters); 151 barrier.await(); 152 } 153 catch (Exception ex) { 154 return; 155 } 156 } 157 158 } 159 160 private static class BuiltinLockLoop extends LockLoop { 161 final int loop(int n) { 162 int sum = 0; 163 int x = 0; 164 while (n-- > 0) { 165 synchronized (this) { 166 x = setValue(LoopHelpers.compute1(getValue())); 167 } 168 sum += LoopHelpers.compute2(x); 169 } 170 return sum; 171 } 172 } 173 174 private static class ReentrantLockLoop extends LockLoop { 175 private final ReentrantLock lock = new ReentrantLock(); 176 final int loop(int n) { 177 final ReentrantLock lock = this.lock; 178 int sum = 0; 179 int x = 0; 180 while (n-- > 0) { 181 lock.lock(); 182 try { 183 x = setValue(LoopHelpers.compute1(getValue())); 184 } 185 finally { 186 lock.unlock(); 187 } 188 sum += LoopHelpers.compute2(x); 189 } 190 return sum; 191 } 192 } 193 194 private static class MutexLoop extends LockLoop { 195 private final Mutex lock = new Mutex(); 196 final int loop(int n) { 197 final Mutex lock = this.lock; 198 int sum = 0; 199 int x = 0; 200 while (n-- > 0) { 201 lock.lock(); 202 try { 203 x = setValue(LoopHelpers.compute1(getValue())); 204 } 205 finally { 206 lock.unlock(); 207 } 208 sum += LoopHelpers.compute2(x); 209 } 210 return sum; 211 } 212 } 213 214 private static class FairReentrantLockLoop extends LockLoop { 215 private final ReentrantLock lock = new ReentrantLock(true); 216 final int loop(int n) { 217 final ReentrantLock lock = this.lock; 218 int sum = 0; 219 int x = 0; 220 while (n-- > 0) { 221 lock.lock(); 222 try { 223 x = setValue(LoopHelpers.compute1(getValue())); 224 } 225 finally { 226 lock.unlock(); 227 } 228 sum += LoopHelpers.compute2(x); 229 } 230 return sum; 231 } 232 } 233 234 private static class ReentrantWriteLockLoop extends LockLoop { 235 private final Lock lock = new ReentrantReadWriteLock().writeLock(); 236 final int loop(int n) { 237 final Lock lock = this.lock; 238 int sum = 0; 239 int x = 0; 240 while (n-- > 0) { 241 lock.lock(); 242 try { 243 x = setValue(LoopHelpers.compute1(getValue())); 244 } 245 finally { 246 lock.unlock(); 247 } 248 sum += LoopHelpers.compute2(x); 249 } 250 return sum; 251 } 252 } 253 254 private static class FairReentrantWriteLockLoop extends LockLoop { 255 final Lock lock = new ReentrantReadWriteLock(true).writeLock(); 256 final int loop(int n) { 257 final Lock lock = this.lock; 258 int sum = 0; 259 int x = 0; 260 while (n-- > 0) { 261 lock.lock(); 262 try { 263 x = setValue(LoopHelpers.compute1(getValue())); 264 } 265 finally { 266 lock.unlock(); 267 } 268 sum += LoopHelpers.compute2(x); 269 } 270 return sum; 271 } 272 } 273 274 private static class SemaphoreLoop extends LockLoop { 275 private final Semaphore sem = new Semaphore(1, false); 276 final int loop(int n) { 277 final Semaphore sem = this.sem; 278 int sum = 0; 279 int x = 0; 280 while (n-- > 0) { 281 sem.acquireUninterruptibly(); 282 try { 283 x = setValue(LoopHelpers.compute1(getValue())); 284 } 285 finally { 286 sem.release(); 287 } 288 sum += LoopHelpers.compute2(x); 289 } 290 return sum; 291 } 292 } 293 294 private static class FairSemaphoreLoop extends LockLoop { 295 private final Semaphore sem = new Semaphore(1, true); 296 final int loop(int n) { 297 final Semaphore sem = this.sem; 298 int sum = 0; 299 int x = 0; 300 while (n-- > 0) { 301 sem.acquireUninterruptibly(); 302 try { 303 x = setValue(LoopHelpers.compute1(getValue())); 304 } 305 finally { 306 sem.release(); 307 } 308 sum += LoopHelpers.compute2(x); 309 } 310 return sum; 311 } 312 } 313 314 private static class ReentrantReadWriteLockLoop extends LockLoop { 315 private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); 316 final int loop(int n) { 317 final Lock rlock = lock.readLock(); 318 final Lock wlock = lock.writeLock(); 319 int sum = 0; 320 int x = 0; 321 while (n-- > 0) { 322 if ((n & 16) != 0) { 323 rlock.lock(); 324 try { 325 x = LoopHelpers.compute1(getValue()); 326 x = LoopHelpers.compute2(x); 327 } 328 finally { 329 rlock.unlock(); 330 } 331 } 332 else { 333 wlock.lock(); 334 try { 335 setValue(x); 336 } 337 finally { 338 wlock.unlock(); 339 } 340 sum += LoopHelpers.compute2(x); 341 } 342 } 343 return sum; 344 } 345 } 346 347 private static class FairReentrantReadWriteLockLoop extends LockLoop { 348 private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(true); 349 final int loop(int n) { 350 final Lock rlock = lock.readLock(); 351 final Lock wlock = lock.writeLock(); 352 int sum = 0; 353 int x = 0; 354 while (n-- > 0) { 355 if ((n & 16) != 0) { 356 rlock.lock(); 357 try { 358 x = LoopHelpers.compute1(getValue()); 359 x = LoopHelpers.compute2(x); 360 } 361 finally { 362 rlock.unlock(); 363 } 364 } 365 else { 366 wlock.lock(); 367 try { 368 setValue(x); 369 } 370 finally { 371 wlock.unlock(); 372 } 373 sum += LoopHelpers.compute2(x); 374 } 375 } 376 return sum; 377 } 378 } 379 }