为了比较一下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
==============================