1 /*
   2  * Copyright (c) 2014 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 package org.openjdk.bench.java.util.concurrent;
  24 
  25 import org.openjdk.jmh.annotations.Benchmark;
  26 import org.openjdk.jmh.annotations.BenchmarkMode;
  27 import org.openjdk.jmh.annotations.Mode;
  28 import org.openjdk.jmh.annotations.OutputTimeUnit;
  29 import org.openjdk.jmh.annotations.Scope;
  30 import org.openjdk.jmh.annotations.Setup;
  31 import org.openjdk.jmh.annotations.State;
  32 import org.openjdk.jmh.infra.Blackhole;
  33 
  34 import java.io.IOException;
  35 import java.io.ObjectInputStream;
  36 import java.util.concurrent.Semaphore;
  37 import java.util.concurrent.TimeUnit;
  38 import java.util.concurrent.locks.AbstractQueuedSynchronizer;
  39 import java.util.concurrent.locks.Condition;
  40 import java.util.concurrent.locks.Lock;
  41 import java.util.concurrent.locks.ReentrantLock;
  42 import java.util.concurrent.locks.ReentrantReadWriteLock;
  43 
  44 @BenchmarkMode(Mode.AverageTime)
  45 @OutputTimeUnit(TimeUnit.NANOSECONDS)
  46 @State(Scope.Benchmark)
  47 public class Locks {
  48 
  49     private ReentrantLock reentrantLock;
  50     private ReentrantLock fairReentrantLock;
  51     private ReentrantReadWriteLock reentrantRWLock;
  52     private ReentrantReadWriteLock fairReentrantRWLock;
  53     private Semaphore semaphore;
  54     private Semaphore fairSemaphore;
  55     private Lock reentrantWriteLock;
  56     private Mutex mutex;
  57 
  58     @Setup
  59     public void setup() {
  60         reentrantLock = new ReentrantLock(false);
  61         fairReentrantLock = new ReentrantLock(true);
  62         reentrantRWLock = new ReentrantReadWriteLock(false);
  63         fairReentrantRWLock = new ReentrantReadWriteLock(true);
  64         semaphore = new Semaphore(1, false);
  65         fairSemaphore = new Semaphore(1, true);
  66         reentrantWriteLock = new ReentrantReadWriteLock(false).writeLock();
  67         mutex = new Mutex();
  68     }
  69 
  70     @Benchmark
  71     public void testSynchronizedBlock() {
  72         synchronized (this) {
  73             Blackhole.consumeCPU(10);
  74         }
  75         Blackhole.consumeCPU(5);
  76     }
  77 
  78     @Benchmark
  79     public void testFairReentrantLock() {
  80         fairReentrantLock.lock();
  81         try {
  82             Blackhole.consumeCPU(10);
  83         } finally {
  84             fairReentrantLock.unlock();
  85         }
  86         Blackhole.consumeCPU(5);
  87     }
  88 
  89     @Benchmark
  90     public void testReentrantLock() {
  91         reentrantLock.lock();
  92         try {
  93             Blackhole.consumeCPU(10);
  94         } finally {
  95             reentrantLock.unlock();
  96         }
  97         Blackhole.consumeCPU(5);
  98     }
  99 
 100     @Benchmark
 101     public void testFairReentrantReadWriteLock() {
 102         fairReentrantRWLock.readLock().lock();
 103         try {
 104             Blackhole.consumeCPU(10);
 105         } finally {
 106             fairReentrantRWLock.readLock().unlock();
 107         }
 108         fairReentrantRWLock.writeLock().lock();
 109         try {
 110             Blackhole.consumeCPU(10);
 111         } finally {
 112             fairReentrantRWLock.writeLock().unlock();
 113         }
 114         Blackhole.consumeCPU(5);
 115     }
 116 
 117     @Benchmark
 118     public void testReentrantReadWriteLock() {
 119         reentrantRWLock.readLock().lock();
 120         try {
 121             Blackhole.consumeCPU(10);
 122         } finally {
 123             reentrantRWLock.readLock().unlock();
 124         }
 125         reentrantRWLock.writeLock().lock();
 126         try {
 127             Blackhole.consumeCPU(10);
 128         } finally {
 129             reentrantRWLock.writeLock().unlock();
 130         }
 131         Blackhole.consumeCPU(5);
 132     }
 133 
 134     @Benchmark
 135     public void testReentrantWriteLock() {
 136         reentrantWriteLock.lock();
 137         try {
 138             Blackhole.consumeCPU(10);
 139         } finally {
 140             reentrantWriteLock.unlock();
 141         }
 142         Blackhole.consumeCPU(5);
 143     }
 144 
 145     @Benchmark
 146     public void testFairSemaphore() throws InterruptedException {
 147         fairSemaphore.acquire();
 148         try {
 149             Blackhole.consumeCPU(10);
 150         } finally {
 151             fairSemaphore.release();
 152         }
 153         Blackhole.consumeCPU(5);
 154     }
 155 
 156     @Benchmark
 157     public void testSemaphore() throws InterruptedException {
 158         semaphore.acquire();
 159         try {
 160             Blackhole.consumeCPU(10);
 161         } finally {
 162             semaphore.release();
 163         }
 164         Blackhole.consumeCPU(5);
 165     }
 166 
 167     @Benchmark
 168     public void testAbstractQueueSynchronizer() {
 169         mutex.lock();
 170         try {
 171             Blackhole.consumeCPU(10);
 172         } finally {
 173             mutex.unlock();
 174         }
 175         Blackhole.consumeCPU(5);
 176     }
 177 
 178     @SuppressWarnings("serial")
 179     private final class Mutex extends AbstractQueuedSynchronizer implements Lock, java.io.Serializable {
 180 
 181         @Override
 182         public boolean isHeldExclusively() {
 183             return getState() == 1;
 184         }
 185 
 186         @Override
 187         public boolean tryAcquire(int acquires) {
 188             return compareAndSetState(0, 1);
 189         }
 190 
 191         @Override
 192         public boolean tryRelease(int releases) {
 193             setState(0);
 194             return true;
 195         }
 196 
 197         @Override
 198         public Condition newCondition() {
 199             return new ConditionObject();
 200         }
 201 
 202         private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException {
 203             s.defaultReadObject();
 204             setState(0); // reset to unlocked state
 205         }
 206 
 207         @Override
 208         public void lock() {
 209             acquire(1);
 210         }
 211 
 212         @Override
 213         public boolean tryLock() {
 214             return tryAcquire(1);
 215         }
 216 
 217         @Override
 218         public void lockInterruptibly() throws InterruptedException {
 219             acquireInterruptibly(1);
 220         }
 221 
 222         @Override
 223         public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException {
 224             return tryAcquireNanos(1, unit.toNanos(timeout));
 225         }
 226 
 227         @Override
 228         public void unlock() {
 229             release(1);
 230         }
 231     }
 232 }