Skip to content

Instantly share code, notes, and snippets.

@lotabout
Created August 21, 2018 01:52
Show Gist options
  • Save lotabout/d69d4664a1d3c6b25e475e8df6faa1d4 to your computer and use it in GitHub Desktop.
Save lotabout/d69d4664a1d3c6b25e475e8df6faa1d4 to your computer and use it in GitHub Desktop.

Revisions

  1. lotabout created this gist Aug 21, 2018.
    291 changes: 291 additions & 0 deletions SyncTest.java
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,291 @@
    import java.util.concurrent.CountDownLatch;
    import java.util.concurrent.CyclicBarrier;
    import java.util.concurrent.atomic.AtomicInteger;
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;

    public class SyncTest {

    private enum TestType {
    SYNCHRONIZED, VOLATILE, ATOMIC, LOCK, FAIR_LOCK
    }

    private final Lock lock = new ReentrantLock(false);
    private final Lock fairLock = new ReentrantLock(true);
    private int synchronizedCounter;
    private int fairLockCounter;
    private int lockCounter;
    private volatile int volatileCounter;
    private final AtomicInteger atomicCounter = new AtomicInteger();

    public static void main(String[] args) throws Exception {
    new SyncTest().run();
    }

    public void run() throws Exception {

    System.out.println("Initializing test...");
    System.out.println();
    System.out.printf("%s (%s) version %s\n", System.getProperty("os.name"), System.getProperty("os.arch"),
    System.getProperty("os.version"));
    System.out.println();
    System.out.printf("java.version %s\n", System.getProperty("java.version"));
    System.out.printf("%s (%s)\n", System.getProperty("java.runtime.name"),
    System.getProperty("java.runtime.version"));
    System.out.printf("%s (build %s, %s)\n", System.getProperty("java.vm.name"),
    System.getProperty("java.vm.version"), System.getProperty("java.vm.info"));
    System.out.println();

    int jvmStabilizationEndValue = 100000;
    int endValue = 10000000;
    System.out.println("JVM Stabilization Count Limit: " + endValue);
    System.out.println("Test Count Limit: " + endValue);
    System.out.println();

    // run to let JVM do any optimizations and stabilize
    runIndividualTest(TestType.SYNCHRONIZED, 1, jvmStabilizationEndValue);
    runIndividualTest(TestType.VOLATILE, 1, jvmStabilizationEndValue);
    runIndividualTest(TestType.ATOMIC, 1, jvmStabilizationEndValue);
    runIndividualTest(TestType.LOCK, 1, jvmStabilizationEndValue);
    runTestsConcurrently(1, jvmStabilizationEndValue);
    runTestsSerially(1, jvmStabilizationEndValue);

    System.out
    .printf("Threads Syncronized Volatile Atomic Lock FairLock Serial Concurrent\n");

    runAllTests(1, endValue);
    runAllTests(2, endValue);
    runAllTests(3, endValue);
    runAllTests(4, endValue);
    runAllTests(5, endValue);
    runAllTests(6, endValue);
    runAllTests(7, endValue);
    runAllTests(8, endValue);
    runAllTests(9, endValue);
    runAllTests(12, endValue);
    runAllTests(24, endValue);
    runAllTests(48, endValue);
    runAllTests(96, endValue);

    System.out.println("\n Test complete");
    }

    private void runAllTests(int threadCount, int endValue) throws Exception {

    long synchronizedElapsed = runIndividualTest(TestType.SYNCHRONIZED, threadCount, endValue);
    long volatileElapsed = runIndividualTest(TestType.VOLATILE, threadCount, endValue);
    long atomicElapsed = runIndividualTest(TestType.ATOMIC, threadCount, endValue);
    long lockElapsed = runIndividualTest(TestType.LOCK, threadCount, endValue);

    long serialElapsed = runTestsSerially(threadCount, endValue);
    long concurrenteElapsed = runTestsConcurrently(threadCount, endValue);

    if (concurrenteElapsed > 0) {

    System.out.printf("%7d %11d %11d %11d %11d %11s %11d %11d\n", threadCount, synchronizedElapsed,
    volatileElapsed, atomicElapsed, lockElapsed, "", serialElapsed, concurrenteElapsed);

    } else if (threadCount <= 2) {

    long fairLockElapsed = runIndividualTest(TestType.FAIR_LOCK, threadCount, endValue);
    System.out.printf("%7d %11d %11d %11d %11d %11d %11d\n", threadCount, synchronizedElapsed, volatileElapsed,
    atomicElapsed, lockElapsed, fairLockElapsed, serialElapsed);
    } else {

    System.out.printf("%7d %11d %11d %11d %11d %11s %11d\n", threadCount, synchronizedElapsed, volatileElapsed,
    atomicElapsed, lockElapsed, "", serialElapsed);
    }
    }

    private long runIndividualTest(final TestType testType, int threadCount, final int endValue) throws Exception {

    final CyclicBarrier testsStarted = new CyclicBarrier(threadCount + 1);
    final CountDownLatch testsComplete = new CountDownLatch(threadCount);

    for (int i = 0; i < threadCount; i++) {
    startTestThread(testType, testsStarted, testsComplete, endValue);
    }

    return waitForTests(testsStarted, testsComplete);
    }

    private long runTestsSerially(int threadCount, final int endValue) throws Exception {

    final CyclicBarrier testsStarted = new CyclicBarrier(threadCount + 1);
    final CountDownLatch testsComplete = new CountDownLatch(threadCount);

    for (int i = 0; i < threadCount; i++) {
    Thread t = new Thread() {
    public void run() {

    try {
    testsStarted.await();

    runSynchronizedTest(endValue);
    runVolatileTest(endValue);
    runAtomicTest(endValue);
    runLockTest(endValue);

    } catch (Throwable t) {
    t.printStackTrace();
    } finally {

    testsComplete.countDown();
    }
    }

    };
    t.start();
    }

    return waitForTests(testsStarted, testsComplete);
    }

    private long runTestsConcurrently(int threadCount, int endValue) throws Exception {

    if (threadCount % 4 != 0) {
    return -1;
    }

    final CyclicBarrier testsStarted = new CyclicBarrier(threadCount + 1);
    final CountDownLatch testsComplete = new CountDownLatch(threadCount);

    threadCount /= 4;
    for (int i = 0; i < threadCount; i++) {
    startTestThread(TestType.SYNCHRONIZED, testsStarted, testsComplete, endValue);
    startTestThread(TestType.VOLATILE, testsStarted, testsComplete, endValue);
    startTestThread(TestType.ATOMIC, testsStarted, testsComplete, endValue);
    startTestThread(TestType.LOCK, testsStarted, testsComplete, endValue);
    }

    return waitForTests(testsStarted, testsComplete);
    }

    private void startTestThread(final TestType testType, final CyclicBarrier testsStarted,
    final CountDownLatch testsComplete, final int endValue) {

    Thread t = new Thread() {
    public void run() {

    try {
    testsStarted.await();

    switch (testType) {
    case SYNCHRONIZED:
    runSynchronizedTest(endValue);
    break;
    case VOLATILE:
    runVolatileTest(endValue);
    break;
    case ATOMIC:
    runAtomicTest(endValue);
    break;
    case LOCK:
    runLockTest(endValue);
    break;
    case FAIR_LOCK:
    runFairLockTest(endValue);
    break;
    }

    } catch (Throwable t) {
    t.printStackTrace();
    } finally {

    testsComplete.countDown();
    }

    }
    };
    t.start();
    }

    private long waitForTests(CyclicBarrier testsStarted, CountDownLatch testsComplete) throws Exception {

    testsStarted.await();
    long startTime = System.currentTimeMillis();

    testsComplete.await();
    long endTime = System.currentTimeMillis();
    reset();

    return endTime - startTime;
    }

    private void reset() {

    synchronized (this) {
    synchronizedCounter = 0;
    }

    volatileCounter = 0;
    atomicCounter.set(0);

    lock.lock();
    try {
    lockCounter = 0;
    } finally {
    lock.unlock();
    }

    fairLock.lock();
    try {
    fairLockCounter = 0;
    } finally {
    fairLock.unlock();
    }
    }

    private void runSynchronizedTest(long endValue) {

    boolean run = true;
    while (run) {
    run = incrementSynchronizedCounter(endValue);
    }
    }

    private synchronized boolean incrementSynchronizedCounter(long endValue) {

    return ++synchronizedCounter < endValue;
    }

    private void runVolatileTest(long endValue) {
    boolean run = true;
    while (run) {
    run = ++volatileCounter < endValue;
    }
    }

    private void runAtomicTest(long endValue) {
    boolean run = true;
    while (run) {
    run = atomicCounter.incrementAndGet() < endValue;
    }
    }

    private void runLockTest(long endValue) {

    boolean run = true;
    while (run) {
    lock.lock();
    try {
    run = ++lockCounter < endValue;
    } finally {
    lock.unlock();
    }
    }
    }

    private void runFairLockTest(long endValue) {

    boolean run = true;
    while (run) {
    fairLock.lock();
    try {
    run = ++fairLockCounter < endValue;
    } finally {
    fairLock.unlock();
    }
    }
    }
    }