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.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 package org.openjdk.bench.java.util.concurrent;
  26 
  27 import org.openjdk.jmh.annotations.Benchmark;
  28 import org.openjdk.jmh.annotations.BenchmarkMode;
  29 import org.openjdk.jmh.annotations.Mode;
  30 import org.openjdk.jmh.annotations.OutputTimeUnit;
  31 import org.openjdk.jmh.annotations.Scope;
  32 import org.openjdk.jmh.annotations.Setup;
  33 import org.openjdk.jmh.annotations.State;
  34 import org.openjdk.jmh.infra.Blackhole;
  35 
  36 import java.io.IOException;
  37 import java.io.ObjectInputStream;
  38 import java.util.concurrent.Semaphore;
  39 import java.util.concurrent.TimeUnit;
  40 import java.util.concurrent.locks.AbstractQueuedSynchronizer;
  41 import java.util.concurrent.locks.Condition;
  42 import java.util.concurrent.locks.Lock;
  43 import java.util.concurrent.locks.ReentrantLock;
  44 import java.util.concurrent.locks.ReentrantReadWriteLock;
  45 
  46 @BenchmarkMode(Mode.AverageTime)
  47 @OutputTimeUnit(TimeUnit.NANOSECONDS)
  48 @State(Scope.Benchmark)
  49 public class Locks {
  50 
  51     private ReentrantLock reentrantLock;
  52     private ReentrantLock fairReentrantLock;
  53     private ReentrantReadWriteLock reentrantRWLock;
  54     private ReentrantReadWriteLock fairReentrantRWLock;
  55     private Semaphore semaphore;
  56     private Semaphore fairSemaphore;
  57     private Lock reentrantWriteLock;
  58     private Mutex mutex;
  59 
  60     @Setup
  61     public void setup() {
  62         reentrantLock = new ReentrantLock(false);
  63         fairReentrantLock = new ReentrantLock(true);
  64         reentrantRWLock = new ReentrantReadWriteLock(false);
  65         fairReentrantRWLock = new ReentrantReadWriteLock(true);
  66         semaphore = new Semaphore(1, false);
  67         fairSemaphore = new Semaphore(1, true);
  68         reentrantWriteLock = new ReentrantReadWriteLock(false).writeLock();
  69         mutex = new Mutex();
  70     }
  71 
  72     @Benchmark
  73     public void testSynchronizedBlock() {
  74         synchronized (this) {
  75             Blackhole.consumeCPU(10);
  76         }
  77         Blackhole.consumeCPU(5);
  78     }
  79 
  80     @Benchmark
  81     public void testFairReentrantLock() {
  82         fairReentrantLock.lock();
  83         try {
  84             Blackhole.consumeCPU(10);
  85         } finally {
  86             fairReentrantLock.unlock();
  87         }
  88         Blackhole.consumeCPU(5);
  89     }
  90 
  91     @Benchmark
  92     public void testReentrantLock() {
  93         reentrantLock.lock();
  94         try {
  95             Blackhole.consumeCPU(10);
  96         } finally {
  97             reentrantLock.unlock();
  98         }
  99         Blackhole.consumeCPU(5);
 100     }
 101 
 102     @Benchmark
 103     public void testFairReentrantReadWriteLock() {
 104         fairReentrantRWLock.readLock().lock();
 105         try {
 106             Blackhole.consumeCPU(10);
 107         } finally {
 108             fairReentrantRWLock.readLock().unlock();
 109         }
 110         fairReentrantRWLock.writeLock().lock();
 111         try {
 112             Blackhole.consumeCPU(10);
 113         } finally {
 114             fairReentrantRWLock.writeLock().unlock();
 115         }
 116         Blackhole.consumeCPU(5);
 117     }
 118 
 119     @Benchmark
 120     public void testReentrantReadWriteLock() {
 121         reentrantRWLock.readLock().lock();
 122         try {
 123             Blackhole.consumeCPU(10);
 124         } finally {
 125             reentrantRWLock.readLock().unlock();
 126         }
 127         reentrantRWLock.writeLock().lock();
 128         try {
 129             Blackhole.consumeCPU(10);
 130         } finally {
 131             reentrantRWLock.writeLock().unlock();
 132         }
 133         Blackhole.consumeCPU(5);
 134     }
 135 
 136     @Benchmark
 137     public void testReentrantWriteLock() {
 138         reentrantWriteLock.lock();
 139         try {
 140             Blackhole.consumeCPU(10);
 141         } finally {
 142             reentrantWriteLock.unlock();
 143         }
 144         Blackhole.consumeCPU(5);
 145     }
 146 
 147     @Benchmark
 148     public void testFairSemaphore() throws InterruptedException {
 149         fairSemaphore.acquire();
 150         try {
 151             Blackhole.consumeCPU(10);
 152         } finally {
 153             fairSemaphore.release();
 154         }
 155         Blackhole.consumeCPU(5);
 156     }
 157 
 158     @Benchmark
 159     public void testSemaphore() throws InterruptedException {
 160         semaphore.acquire();
 161         try {
 162             Blackhole.consumeCPU(10);
 163         } finally {
 164             semaphore.release();
 165         }
 166         Blackhole.consumeCPU(5);
 167     }
 168 
 169     @Benchmark
 170     public void testAbstractQueueSynchronizer() {
 171         mutex.lock();
 172         try {
 173             Blackhole.consumeCPU(10);
 174         } finally {
 175             mutex.unlock();
 176         }
 177         Blackhole.consumeCPU(5);
 178     }
 179 
 180     @SuppressWarnings("serial")
 181     private final class Mutex extends AbstractQueuedSynchronizer implements Lock, java.io.Serializable {
 182 
 183         @Override
 184         public boolean isHeldExclusively() {
 185             return getState() == 1;
 186         }
 187 
 188         @Override
 189         public boolean tryAcquire(int acquires) {
 190             return compareAndSetState(0, 1);
 191         }
 192 
 193         @Override
 194         public boolean tryRelease(int releases) {
 195             setState(0);
 196             return true;
 197         }
 198 
 199         @Override
 200         public Condition newCondition() {
 201             return new ConditionObject();
 202         }
 203 
 204         private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException {
 205             s.defaultReadObject();
 206             setState(0); // reset to unlocked state
 207         }
 208 
 209         @Override
 210         public void lock() {
 211             acquire(1);
 212         }
 213 
 214         @Override
 215         public boolean tryLock() {
 216             return tryAcquire(1);
 217         }
 218 
 219         @Override
 220         public void lockInterruptibly() throws InterruptedException {
 221             acquireInterruptibly(1);
 222         }
 223 
 224         @Override
 225         public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException {
 226             return tryAcquireNanos(1, unit.toNanos(timeout));
 227         }
 228 
 229         @Override
 230         public void unlock() {
 231             release(1);
 232         }
 233     }
 234 }