`
bruce008
  • 浏览: 173021 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

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)。

分享到:
评论

相关推荐

    ReentrantLock与synchronized区别

    java语言 并发编程 ReentrantLock与synchronized区别 详解

    Java并发之ReentrantLock类源码解析

    2. ReentrantLock(boolean fair) 其中,fair参数表示是否使用公平锁,如果为true,则使用公平锁,否则使用非公平锁。 ReentrantLock的锁机制 ReentrantLock的锁机制是通过CAS(Compare-And-Swap)操作来实现的。...

    Java多线程之ReentrantLock与Condition - 平凡希 - 博客园1

    Java中的`ReentrantLock`是Java并发包`java.util.concurrent.locks`中的一个高级锁机制,它是可重入的互斥锁,具有与`synchronized`关键字相似的同步性,但提供了更多的灵活性和控制功能。本篇文章将深入探讨`...

    java ReentrantLock详解.docx

    - 在`ServiceIsFair`示例中,我们创建了`ReentrantLock`实例,并在`serviceMethod`中使用`lock.isFair()`检查锁的公平性。 - `ServiceIsHeldByCurrentThread`展示了如何使用`isHeldByCurrentThread()`检查当前线程...

    ReentrantLock与synchronized

    在Java多线程编程中,`ReentrantLock`和`synchronized`都是用于实现线程同步的重要工具,确保在并发环境中数据的一致性和正确性。两者虽然都能实现互斥访问,但在功能、性能以及使用场景上有所不同。下面我们将深入...

    Java中ReentrantLock的使用.docx

    但在JDK 6.0及以后的版本中,synchronized的性能得到了显著提升,与ReentrantLock的性能差距已经不大。尽管如此,ReentrantLock仍然有其独特之处,比如它可以提供公平锁和非公平锁的选择,支持中断锁等待,以及更细...

    ReentrantLock 与 synchronized 简介

    ### ReentrantLock 与 synchronized 的比较 #### 一、引言 在Java中,多线程和并发控制一直是程序员关注的重点。随着Java的发展,其语言本身及标准库提供了丰富的工具来帮助开发者处理并发问题。其中,`...

    ReentrantLock解析

    与synchronized关键字相比,ReentrantLock提供了更高的灵活性,如尝试加锁、定时加锁和公平锁等功能。本文将深入探讨ReentrantLock的实现原理,主要涉及其内部类AbstractQueuedSynchronizer(AQS)和Unsafe工具类。 ...

    ReentrantLock源码的使用问题详解.docx

    《ReentrantLock源码详解与应用》 ReentrantLock,可重入锁,是Java并发编程中一个重要的锁实现,它提供了比synchronized更高级别的控制能力,包括公平性和非公平性选择。本文将深入探讨ReentrantLock的原理,特别...

    Lock、Synchoronized和ReentrantLock的使用

    ReentrantLock 的特点是拥有与 Synchronized 相同的并发性和内存语义,但是添加了类似锁投票、定时锁等候和可Interrupt 锁等候的一些特性。此外,它还提供了在激烈争用情况下更佳的性能。 八、Reentrant 锁 ...

    ReentrantLock 实现原理 1

    默认情况下,ReentrantLock 使用非公平锁,它的效率和吞吐量都比公fair锁高的多。 获取锁的过程中,ReentrantLock 使用了 AQS 的 acquiring 机制。首先,ReentrantLock 会调用 sync 的 lock 方法,而这个方法是一个...

    ReentrantLock的使用及注意事项

    ReentrantLock的使用及注意事项

    ReentrantLock源码分析

    与传统的synchronized关键字相比,ReentrantLock提供了更多控制手段,比如可以指定是否公平锁、支持中断等特性。 #### 二、ReentrantLock的主要功能 ReentrantLock提供了多种锁获取方式,包括但不限于: - `lock()`...

    一张图将整个ReentrantLock流程看懂

    一张图将整个ReentrantLock流程看懂,干货满满 一张图将整个ReentrantLock流程看懂,干货满满 一张图将整个ReentrantLock流程看懂,干货满满 一张图将整个ReentrantLock流程看懂,干货满满 一张图将整个...

    ReentrantLock代码剖析之ReentrantLock_lock

    如果期望值`expect`与当前`state`相等,那么更新`state`为`update`值并返回`true`,否则返回`false`。 当线程成功获取锁后,`state`会被递增,表示锁已被持有。如果线程在持有锁的过程中再次请求锁,`ReentrantLock...

    ReentrantLock lock方法注释

    ReentrantLock lock方法注释

    教你完全理解ReentrantLock重入锁

    1. ReentrantLock的介绍 ReentrantLock重入锁,是实现Lock接口的一个类,也是在实际编程中使用频率很高的一个锁,支持重入性,表示能够对共享资源能够重复加锁,即当前线程获取该锁再次获取不会被阻塞。在java...

    22 到底哪把锁更适合你?—synchronized与ReentrantLock对比.pdf

    在Java中,有两种主要的锁机制:内置的`synchronized`关键字和显式的`ReentrantLock`类。这两者各有优劣,适用于不同的场景。下面我们将详细讨论它们的区别、性能、特性以及使用上的差异。 1. **功能对比**: - `...

    使用ReentrantLock和Lambda表达式让同步更

    `ReentrantLock`是Java并发包`java.util.concurrent.locks`中的一个类,它是可重入的互斥锁,具备与`synchronized`相同的基本行为,但增加了许多高级功能。以下是一些`ReentrantLock`的主要特性: 1. **可重入性**...

Global site tag (gtag.js) - Google Analytics