爲了比較一下ReentrantLock和synchronized的性能,作了一下性能測試: java
參考http://my.oschina.net/leoson/blog/107327 算法
得出結論: 多線程
(1)使用Lock的性能比使用synchronized關鍵字要提升4~5倍; 併發
(2)使用信號量實現同步的速度大約比synchronized要慢10~20%; 框架
(3)使用atomic包的AtomicInter速度是比Lock要快1一個數量級。 ide
ReentrantLock 類
java.util.concurrent.lock 中的 Lock 框架是鎖定的一個抽象,它容許把鎖定的實現做爲 Java 類,而不是做爲語言的特性來實現。這就爲 Lock 的多種實現留下了空間,各類實現可能有不一樣的調度算法、性能特性或者鎖定語義。ReentrantLock 類實現了 Lock,它擁有與 synchronized 相同的併發性和內存語義,可是添加了相似鎖投票、定時鎖等候和可中斷鎖等候的一些特性。此外,它還提供了在激烈爭用狀況下更佳的性能。(換句話說,當許多線程都想訪問共享資源時,JVM 能夠花更少的時候來調度線程,把更多時間用在執行線程上。) 性能
reentrant 鎖意味着什麼呢?簡單來講,它有一個與鎖相關的獲取計數器,若是擁有鎖的某個線程再次獲得鎖,那麼獲取計數器就加1,而後鎖須要被釋放兩次才能得到真正釋放。這模仿了 synchronized 的語義;若是線程進入由線程已經擁有的監控器保護的 synchronized 塊,就容許線程繼續進行,當線程退出第二個(或者後續)synchronized 塊的時候,不釋放鎖,只有線程退出它進入的監控器保護的第一個 synchronized 塊時,才釋放鎖。 測試
在查看清單 1 中的代碼示例時,能夠看到 Lock 和 synchronized 有一點明顯的區別 —— lock 必須在 finally 塊中釋放。不然,若是受保護的代碼將拋出異常,鎖就有可能永遠得不到釋放!這一點區別看起來可能沒什麼,可是實際上,它極爲重要。忘記在 finally 塊中釋放鎖,可能會在程序中留下一個定時bomb,當有一天bomb爆炸時,您要花費很大力氣纔有找到源頭在哪。而使用同步,JVM 將確保鎖會得到自動釋放。 ui
Test的源碼: this
import java.util.concurrent.BrokenBarrierException; import java.util.concurrent.CyclicBarrier; import java.util.concurrent.ExecutorService; public abstract class Test { protected String id; protected CyclicBarrier barrier; protected long count; protected int threadNum; protected ExecutorService executor; public Test(String id, CyclicBarrier barrier, long count, int threadNum, ExecutorService executor) { this.id = id; this.barrier = barrier; this.count = count; this.threadNum = threadNum; this.executor = executor; } public void startTest() { long start = System.currentTimeMillis(); for (int j = 0; j < threadNum; j++) { executor.execute(new Thread() { // @Override public void run() { for (int i = 0; i < count; i++) { test(); } try { barrier.await(); } catch (InterruptedException e) { e.printStackTrace(); } catch (BrokenBarrierException e) { e.printStackTrace(); } } }); } try { barrier.await(); } catch (InterruptedException e) { e.printStackTrace(); } catch (BrokenBarrierException e) { e.printStackTrace(); } // 全部線程執行完成以後,纔會跑到這一步 long duration = System.currentTimeMillis() - start; System.out.println(id + " = " + duration); } protected abstract void test(); }
測試類ReentreLockTest 源碼:
import java.util.concurrent.BrokenBarrierException; import java.util.concurrent.CyclicBarrier; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Semaphore; import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class ReentreLockTest { private static long COUNT = 1000000; private static Lock lock = new ReentrantLock(); private static long lockCounter = 0; private static long syncCounter = 0; private static long semaCounter = 0; private static AtomicLong atomicCounter = new AtomicLong(0); private static Object syncLock = new Object(); private static Semaphore mutex = new Semaphore(1); public static void testLock(int num, int threadCount) { } static long getLock() { lock.lock(); try { return lockCounter; } finally { lock.unlock(); } } static long getSync() { synchronized (syncLock) { return syncCounter; } } static long getAtom() { return atomicCounter.get(); } static long getSemaphore() throws InterruptedException { mutex.acquire(); try { return semaCounter; } finally { mutex.release(); } } static long getLockInc() { lock.lock(); try { return ++lockCounter; } finally { lock.unlock(); } } static long getSyncInc() { synchronized (syncLock) { return ++syncCounter; } } static long getAtomInc() { return atomicCounter.getAndIncrement(); } static class SemaTest extends Test { public SemaTest(String id, CyclicBarrier barrier, long count, int threadNum, ExecutorService executor) { super(id, barrier, count, threadNum, executor); } @Override protected void test() { try { getSemaphore(); } catch (InterruptedException e) { e.printStackTrace(); } } } static class LockTest extends Test { public LockTest(String id, CyclicBarrier barrier, long count, int threadNum, ExecutorService executor) { super(id, barrier, count, threadNum, executor); } @Override protected void test() { getLock(); } } static class SyncTest extends Test { public SyncTest(String id, CyclicBarrier barrier, long count, int threadNum, ExecutorService executor) { super(id, barrier, count, threadNum, executor); } @Override protected void test() { getSync(); } } static class AtomicTest extends Test { public AtomicTest(String id, CyclicBarrier barrier, long count, int threadNum, ExecutorService executor) { super(id, barrier, count, threadNum, executor); } @Override protected void test() { getAtom(); } } public static void test(String id, long count, int threadNum, ExecutorService executor) { final CyclicBarrier barrier = new CyclicBarrier(threadNum + 1, new Thread() { @Override public void run() { } }); System.out.println("=============================="); System.out.println("count = " + count + "/t" + "Thread Count = " + threadNum); new LockTest("Lock ", barrier, COUNT, threadNum, executor).startTest(); new SyncTest("Sync ", barrier, COUNT, threadNum, executor).startTest(); new AtomicTest("Atom ", barrier, COUNT, threadNum, executor) .startTest(); new SemaTest("Sema ", barrier, COUNT, threadNum, executor) .startTest(); System.out.println("=============================="); } public static void main(String[] args) { for (int i = 1; i < 5; i++) { ExecutorService executor = Executors.newFixedThreadPool(10 * i); test("", COUNT * i, 10 * i, executor); } } }
結果:
==============================
count = 1000000/tThread Count = 10
Lock = 417
Sync = 1876
Atom = 34
Sema = 3749
==============================
==============================
count = 2000000/tThread Count = 20
Lock = 815
Sync = 3480
Atom = 69
Sema = 7448
==============================
==============================
count = 3000000/tThread Count = 30
Lock = 1234
Sync = 5163
Atom = 93
Sema = 10609
==============================
==============================
count = 4000000/tThread Count = 40
Lock = 1611
Sync = 6934
Atom = 142
Sema = 13243
==============================