1. 程式人生 > 實用技巧 >使用微基準測試框架JMH對ReentrantLock的公平與非公平鎖進行效能測試

使用微基準測試框架JMH對ReentrantLock的公平與非公平鎖進行效能測試

目錄


前言

最近在閱讀ReentrantLock原始碼的時候, 發現了Lock有公平和不公平兩種鎖, 查閱相關資料與部落格後得知公平鎖和非公平鎖的效能是不一樣的, 非公平鎖的效能會優於公平鎖.
因為FairLock在獲取鎖時, 永遠是等待時間最長的執行緒獲取到鎖, 這樣當執行緒釋放鎖以後, 如果還想繼續再獲取鎖, 就必須去Sync佇列尾部進行排隊, 這樣就會發生頻繁的執行緒切換, 所以非公平鎖的吞吐量就要強於公平鎖

Benchmark

是openjdk提供一種基準測試的框架, 支援多種粒度的效能測試. 官方文件: https://github.com/openjdk/jmh

效能測試程式碼

利用CountDownLatch配合JMH, 測試極端條件下(獲取鎖之後立馬釋放鎖, 不斷迴圈), 不同的執行緒數量迴圈10000次加鎖解鎖的平均時間

@Fork(1)
@Threads(1)
@Warmup(iterations = 1)
@State(Scope.Benchmark)
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.MILLISECONDS)
@Measurement(iterations = 5, time = 5, timeUnit = TimeUnit.SECONDS)
public class BenchmarkFairAndNonFair {

    @Param({"10", "50", "100", "300", "500"})
    private int threadNum;

    private static final int FOREACH_COUNT = 10000;

    @Benchmark
    public void testFairLock() throws InterruptedException {
        final Lock fairLock = new ReentrantLock(true);
        final CountDownLatch countDownLatch = new CountDownLatch(threadNum);
        List<Thread> threads = new ArrayList<>();
        for (int i = 0; i < threadNum; i++) {
            threads.add(new Thread(() -> {
                for (int j = 0; j < FOREACH_COUNT; j++) {
                    fairLock.lock();
                    fairLock.unlock();
                }
                countDownLatch.countDown();
            }));
        }
        threads.forEach(thread -> thread.start());
        // main wait all thread
        countDownLatch.await();
    }

    @Benchmark
    public void testNonFairLock() throws InterruptedException {
        final Lock nonFairLock = new ReentrantLock(false);
        final CountDownLatch countDownLatch = new CountDownLatch(threadNum);
        List<Thread> threads = new ArrayList<>();
        for (int i = 0; i < threadNum; i++) {
            threads.add(new Thread(() -> {
                for (int j = 0; j < FOREACH_COUNT; j++) {
                    nonFairLock.lock();
                    nonFairLock.unlock();
                }
                countDownLatch.countDown();
            }));
        }
        threads.forEach(thread -> thread.start());
        // main wait all thread
        countDownLatch.await();
    }

    public static void main(String[] args) throws RunnerException {
        Options options = new OptionsBuilder()
                .include(BenchmarkFairAndNonFair.class.getSimpleName())
                .build();
        new Runner(options).run();
    }

}

效能測試結果

# Run complete. Total time: 00:08:23

Benchmark                                (threadNum)  Mode  Cnt      Score      Error  Units
BenchmarkFairAndNonFair.testFairLock              10  avgt    5    335.780 ±   13.599  ms/op
BenchmarkFairAndNonFair.testFairLock              50  avgt    5   1856.063 ±  127.977  ms/op
BenchmarkFairAndNonFair.testFairLock             100  avgt    5   3917.435 ±  673.222  ms/op
BenchmarkFairAndNonFair.testFairLock             300  avgt    5  14387.132 ± 3668.159  ms/op
BenchmarkFairAndNonFair.testFairLock             500  avgt    5  29424.262 ± 2485.551  ms/op
BenchmarkFairAndNonFair.testNonFairLock           10  avgt    5      2.383 ±    0.094  ms/op
BenchmarkFairAndNonFair.testNonFairLock           50  avgt    5     11.402 ±    0.820  ms/op
BenchmarkFairAndNonFair.testNonFairLock          100  avgt    5     23.525 ±    1.628  ms/op
BenchmarkFairAndNonFair.testNonFairLock          300  avgt    5     70.299 ±    0.746  ms/op
BenchmarkFairAndNonFair.testNonFairLock          500  avgt    5    121.046 ±    2.014  ms/op

結論

從測試結果可以可看出, 非公平鎖的效能確實比公平鎖要好, 而且執行緒數量越多, 差別越是明顯