首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 网络技术 > 网络基础 >

ReentrantLock Fair 与 Unfair 的硕大差异

2012-08-11 
ReentrantLockFair 与 Unfair 的巨大差异ReentrantLock ?可重入的锁是我们平常除了intrinsic ?lock ?(也就

ReentrantLock Fair 与 Unfair 的巨大差异

ReentrantLock ?可重入的锁是我们平常除了intrinsic ?lock ?(也就是 synchronized 方法, synchronized block)之外用得最多的了同步方式了。 一般情况下 我们用?ReentrantLock ?的时候就是用它的默认建构函数方式?

? ? ?new?ReentrantLock ?();

但其实它带一个 参数 是否 fair。如果是true ?也就是FairSync 所在有多个线程同时竞争这个锁得时候, 会考虑公平性尽可能的让不同的线程公平。 这个公平其实是有很大的性能损失换来的。下面有个例子 : ?\

?

package com.bwang.concurrent;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;import java.util.concurrent.CyclicBarrier;import static java.lang.System.out;public final class TestLocks implements Runnable{    public enum LockType { JVM, JUC }    public static LockType lockType;    public static final long ITERATIONS = 5L * 1000L * 1000L;    public static long counter = 0L;    public static final Object jvmLock = new Object();    public static final Lock jucLock = new ReentrantLock(false);    private static int numThreads;    private final long iterationLimit;    private final CyclicBarrier barrier;    private long localCounter = 0L;    public long getLocalCounter()     {    return localCounter;    }     public TestLocks(final CyclicBarrier barrier, final long iterationLimit)    {        this.barrier = barrier;        this.iterationLimit = iterationLimit;    }    public static void main(final String[] args) throws Exception    {        lockType = LockType.valueOf("JUC");        numThreads = Integer.parseInt("8");        final long start = System.nanoTime();        runTest(numThreads, ITERATIONS);        final long duration = System.nanoTime() - start;        out.printf("%d threads, duration %,d (ns)\n", numThreads, duration);        out.printf("%,d ns/op\n", duration / ITERATIONS);        out.printf("%,d ops/s\n", (ITERATIONS * 1000000000L) / duration);        out.println("counter = " + counter);    }    private static void runTest(final int numThreads, final long iterationLimit)        throws Exception    {        CyclicBarrier barrier = new CyclicBarrier(numThreads);        Thread[] threads = new Thread[numThreads];        TestLocks[] testLocks = new TestLocks[numThreads];        for (int i = 0; i < threads.length; i++)        {        testLocks[i] = new TestLocks(barrier, iterationLimit);            threads[i] = new Thread(testLocks[i]);        }        for (Thread t : threads)        {            t.start();        }        for (Thread t : threads)        {            t.join();        }        for (int i = 0; i < threads.length; i++)        {            out.printf("%d thread, local counter = %,d\n", i, testLocks[i].getLocalCounter());        }    }    public void run()    {        try        {            barrier.await();        }        catch (Exception e)        {            // don't care        }        switch (lockType)        {            case JVM: jvmLockInc(); break;            case JUC: jucLockInc(); break;        }    }    private void jvmLockInc()    {                while (true)        {        long count = 0;            synchronized (jvmLock)            {                ++counter;                count = counter;            }            localCounter++;            if (count >= iterationLimit)  {            break;            }        }    }    private void jucLockInc()    {        while (true)        {            long count = 0L;            jucLock.lock();            try            {                ++counter;                count = counter;            }            finally            {                jucLock.unlock();            }            localCounter++;            if (count >= iterationLimit)  {            break;            }        }    }}

?

?

我们简单用N个线程来同步一个counter ?5,000,000次。 如果是?new ReentrantLock(true) 也就是 FairSync 方式 :

?

?

0 thread, local counter = 624,822

1 thread, local counter = 625,135

2 thread, local counter = 624,936

3 thread, local counter = 624,800

4 thread, local counter = 625,007

5 thread, local counter = 624,921

6 thread, local counter = 625,298

7 thread, local counter = 625,088

8 threads, duration 16,553,236,994 (ns)

3,310 ns/op

302,055 ops/s

counter = 5000007

?

?

可以看到8 个线程 每个线程的获取lock都很接近 但是它要 3310 个ns 来进行一次。 ? 如果采用??如果是?new ReentrantLock(false) 就是 UnfairSync 方式:

0 thread, local counter = 626,786

1 thread, local counter = 594,983

2 thread, local counter = 590,274

3 thread, local counter = 688,725

4 thread, local counter = 588,090

5 thread, local counter = 586,885

6 thread, local counter = 732,210

7 thread, local counter = 592,054

8 threads, duration 425,844,254 (ns)

85 ns/op

11,741,381 ops/s

counter = 5000007

虽然 每个thread 获取lock 的次数差异很大 从 ? 592,054到 ?732,210, ?但每次操作自需要 85 ns。 ?3310 对 85 这个差异太大聊。 ?

如果我们用intrinsic lock 的方法 结果如下:

?

0 thread, local counter = 498,363

1 thread, local counter = 512,603

2 thread, local counter = 799,367

3 thread, local counter = 500,946

4 thread, local counter = 824,935

5 thread, local counter = 652,921

6 thread, local counter = 692,219

7 thread, local counter = 518,653

8 threads, duration 877,777,848 (ns)

175 ns/op

5,696,202 ops/s

counter = 5000007

?

intrinsic lock 也应该是unfair 的方式, 每个线程获取的机会差异比较大, 每个操作需要 175ns。 ?比 unfair 的?ReentrantLock ?性能差些。 ??

?

得出的结果是 如果我们仅考虑同步锁得性能不需要考虑公平性优先考虑?

? ? ??new ReentrantLock(false) ? ?

再次是?intrinsic lock

万不得已的必须要FairSync 的情况下才用?new ReentrantLock(true)。

热点排行