Created
August 21, 2018 01:52
-
-
Save lotabout/d69d4664a1d3c6b25e475e8df6faa1d4 to your computer and use it in GitHub Desktop.
Revisions
-
lotabout created this gist
Aug 21, 2018 .There are no files selected for viewing
This file contains hidden or 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 charactersOriginal 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(); } } } }