In JDK5, old synchornized keyword is much slower than ReentrantLock and Semaphore implementation. It is worth to mention that the spinlock is the fastest.
import java.util.concurrent.*; import java.util.concurrent.locks.*; import java.util.concurrent.atomic.*; public class SyncExample { // Thread starting latch CountDownLatch startSignal; int dummy; // old synchornized keyword public void synchornized_method(int n) { try { startSignal.await(); } catch(InterruptedException ie) { ie.printStackTrace(); } synchronized(this) { System.out.println(dummy + “+” + n + “=” + (dummy+n)); dummy++; } } // lock approach private ReentrantLock lock = new ReentrantLock(); public void lock_method(int n) { try { startSignal.await(); } catch(InterruptedException ie) { ie.printStackTrace(); } lock.lock(); try { System.out.println(dummy + “+” + n + “=” + (dummy+n)); dummy++; } finally { lock.unlock(); } } // semaphore approach private Semaphore s = new Semaphore(1); public void semaphore_method(int n) { try { startSignal.await(); } catch(InterruptedException ie) { ie.printStackTrace(); } try { s.acquire(); System.out.println(dummy + “+” + n + “=” + (dummy+n)); dummy++; } catch(InterruptedException ie) { ie.printStackTrace(); } finally { s.release(); } } // spin lock approach // to get dummy value from memory, we need to make it atomic AtomicInteger ai_dummy; public void spin_lock(int n) { int local_dummy = ai_dummy.getAndIncrement(); System.out.println(local_dummy + “+” + n + “=” + (local_dummy + n)); } private void waitSomeTime() { try { Thread.sleep(1000); } catch(InterruptedException ie) {} } private void waitLittleTime() { try { Thread.sleep(10); } catch(InterruptedException ie) {} } public void syncTest() { startSignal = new CountDownLatch(1); dummy = 0; ExecutorService exec = Executors.newFixedThreadPool(1000); for (int i = 0; i < 1000; i++) { final int j = i; exec.submit(new Runnable() { public void run() { synchornized_method(j); } }); } // no new thread exec.shutdown(); // give some time to make all threads started waitSomeTime(); // now, time the execs long start = System.currentTimeMillis(); // give start signals startSignal.countDown(); while (true) { if (exec.isTerminated()) break; waitLittleTime(); } System.out.println(“Elapsed time for synchornized: “ + (System.currentTimeMillis() - start)); } public void lockTest() { startSignal = new CountDownLatch(1); dummy = 0; ExecutorService exec = Executors.newFixedThreadPool(1000); for (int i = 0; i < 1000; i++) { final int j = i; exec.submit(new Runnable() { public void run() { lock_method(j); } }); } // no new thread exec.shutdown(); // give some time to make all threads started waitSomeTime(); // now, time the execs long start = System.currentTimeMillis(); // give start signals startSignal.countDown(); while (true) { if (exec.isTerminated()) break; waitLittleTime(); } System.out.println(“Elapsed time for lock: “ + (System.currentTimeMillis() - start)); } public void semaTest() { startSignal = new CountDownLatch(1); dummy = 0; ExecutorService exec = Executors.newFixedThreadPool(1000); for (int i = 0; i < 1000; i++) { final int j = i; exec.submit(new Runnable() { public void run() { semaphore_method(j); } }); } // no new thread exec.shutdown(); // give some time to make all threads started waitSomeTime(); // now, time the execs long start = System.currentTimeMillis(); // give start signals startSignal.countDown(); while (true) { if (exec.isTerminated()) break; waitLittleTime(); } System.out.println(“Elapsed time for semaphore: “ + (System.currentTimeMillis() - start)); } public void spinLockTest() { startSignal = new CountDownLatch(1); ai_dummy = new AtomicInteger(0); ExecutorService exec = Executors.newFixedThreadPool(1000); for (int i = 0; i < 1000; i++) { final int j = i; exec.submit(new Runnable() { public void run() { spin_lock(j); } }); } // no new thread exec.shutdown(); // give some time to make all threads started waitSomeTime(); // now, time the execs long start = System.currentTimeMillis(); // give start signals startSignal.countDown(); while (true) { if (exec.isTerminated()) break; waitLittleTime(); } System.out.println(“Elapsed time for spinlock: “ + (System.currentTimeMillis() - start)); } public static void main(String[] args) { SyncExample se = new SyncExample(); for (int i = 0; i < 10; i++) { se.syncTest(); se.lockTest(); se.semaTest(); se.spinLockTest(); se.waitSomeTime(); } } }
Because the ‘works’ done by threads was way too simple, I did not have to spin,i.e., while (true). But the situation is not much different even if your work is more quite complex than above.
Note: The following conclusion is incorrect. Please read the comments of this article.
I’ve computed trimmed mean (10%) of execution times and the result is as follows:
Synchornized: 1139.4 ms
Lock: 817.7 ms
Semaphore: 823.8 ms
Spinlock: 1.1 ms
Which obviously proves the slowness of synchornized keyword. If the system performance is your primary concerns,
use ReentrantLock, Semaphore, and Spinlock. But be aware that you must release locks&semaphores in finally clauses.
Leave a Reply