Last active
April 29, 2018 21:34
-
-
Save nikolaybotev/bc8cc1cdfa2f7cc212a915c487771d53 to your computer and use it in GitHub Desktop.
Benchmark Similar to https://mechanical-sympathy.blogspot.com/2011/09/single-writer-principle.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.util.concurrent.BrokenBarrierException; | |
import java.util.concurrent.CountDownLatch; | |
import java.util.concurrent.CyclicBarrier; | |
import java.util.concurrent.TimeUnit; | |
import java.util.concurrent.atomic.AtomicLong; | |
import java.util.concurrent.locks.Lock; | |
import java.util.concurrent.locks.ReentrantLock; | |
public class TestIncrement { | |
public static void main(String[] args) throws InterruptedException, BrokenBarrierException { | |
runTest(new CounterBare(), "Single thread", 1); | |
runTest(new CounterWithVolatile(), "Single thread with volatile", 1); | |
runTest(new CounterWithCAS(), "Single thread with CAS", 1); | |
runTest(new CounterWithSynchronized(), "Single thread with synchronized", 1); | |
runTest(new CounterWithLock(), "Single thread with lock", 1); | |
runTest(new CounterWithCAS(), "Two threads with CAS", 2); | |
runTest(new CounterWithSynchronized(), "Two threads with synchronized", 2); | |
runTest(new CounterWithLock(), "Two threads with lock", 2); | |
} | |
private static void runTest(final Counter counter, final String name, final int threadCount) | |
throws InterruptedException, BrokenBarrierException { | |
final CountDownLatch endLatch = new CountDownLatch(threadCount); | |
final int warmUpIterations = 100_000; | |
final int iterations = 500_000_000; | |
final int perThreadIterations = iterations / threadCount; | |
final CyclicBarrier startBarrier = new CyclicBarrier(threadCount + 1); | |
for (int i = 0; i < threadCount; i++) { | |
@SuppressWarnings("Convert2Lambda") | |
Thread thread = new Thread(new Runnable() { | |
@Override | |
public void run() { | |
for (int a = 0; a < warmUpIterations; a++) { | |
runIterations(counter, 5); | |
} | |
for (int a = 0; a < 5; a++) { | |
runIterations(counter, warmUpIterations); | |
} | |
try { | |
startBarrier.await(); | |
} catch (InterruptedException | BrokenBarrierException e) { | |
throw new IllegalStateException(e); | |
} | |
runIterations(counter, perThreadIterations); | |
endLatch.countDown(); | |
} | |
}); | |
thread.start(); | |
} | |
startBarrier.await(); | |
long startNanos = System.nanoTime(); | |
endLatch.await(); | |
long elapsedNanos = System.nanoTime() - startNanos; | |
assert counter.getValue() == iterations + (threadCount * 10 * warmUpIterations); | |
System.out.printf("%40s: %,d ms%n", name, TimeUnit.NANOSECONDS.toMillis(elapsedNanos)); | |
} | |
private static void runIterations(Counter c, int n) { | |
for (int j = 0; j < n; j++) { | |
c.increment(); | |
} | |
} | |
private interface Counter { | |
void increment(); | |
long getValue(); | |
} | |
private static class CounterBare implements Counter { | |
private long value = 0; | |
@Override | |
public void increment() { | |
value++; | |
} | |
@Override | |
public long getValue() { | |
return value; | |
} | |
} | |
private static class CounterWithVolatile implements Counter { | |
private volatile long value = 0; | |
@SuppressWarnings("NonAtomicOperationOnVolatileField") | |
@Override | |
public void increment() { | |
value++; | |
} | |
@Override | |
public long getValue() { | |
return value; | |
} | |
} | |
private static class CounterWithCAS implements Counter { | |
private AtomicLong value = new AtomicLong(0); | |
@Override | |
public void increment() { | |
value.incrementAndGet(); | |
} | |
@Override | |
public long getValue() { | |
return value.get(); | |
} | |
} | |
private static class CounterWithSynchronized implements Counter { | |
private final Object lock = new Object(); | |
private long value = 0; | |
@Override | |
public void increment() { | |
synchronized (lock) { | |
value++; | |
} | |
} | |
@Override | |
public long getValue() { | |
return value; | |
} | |
} | |
private static class CounterWithLock implements Counter { | |
private final Lock lock = new ReentrantLock(); | |
private long value = 0; | |
@Override | |
public void increment() { | |
lock.lock(); | |
try { | |
value++; | |
} finally { | |
lock.unlock(); | |
} | |
} | |
@Override | |
public long getValue() { | |
return value; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment