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(); } } } }