谷歌镜像 伍佰目录 短网址
  当前位置:海洋目录网 » 站长资讯 » 站长资讯 » 文章详细 订阅RssFeed

ReentrantLock非公平锁与公平锁的实现

来源:本站原创 浏览:90次 时间:2022-10-01
ReentrantLock非公平锁与公平锁的实现

在文章开始之前,大家复习一遍锁的分类:

ReentrantLock是根据传入的参数来决定是否使用公平锁,默认使用非公平锁:

  • 公平锁/非公平锁

    当多个线程来取锁的时候,按照规则排队等锁即为公平锁,不按照规则排队的即为非公平锁, Synchronized就是一个典型的非公平锁,而ReentrantLock
     是根据AQS来实现线程的一个调度达到公平锁与非公平锁的一个切换。

  • 可重入锁

    一个带锁的方法块可以调用另一个带锁的方法块,也就是在执行线程的期间,前后会用到两个锁,可重入锁就有效的避免了前后死锁的情况。

  • 独享锁/共享锁

    独享锁是该锁只能被一个线程所持有,共享锁是值该锁可以被多个线程所持有。
     ReentrantLock和Synchronized都是独享锁,而ReadWriteLock中读锁是共享锁,写锁是独享锁

  • 乐观锁/悲观锁

    悲观锁适合写操作,乐观锁适合读操作。

  • 分段锁

    是针对部分数据设置的一种锁,例如我要改变某一个有规则的数据链,我定位在某一块,只需要锁住这一块的数据,就能保证整体的数据一致。
     例如在 CurrentHashMap中,根据hashcode定位数据块,实现分段锁。

  • 偏向锁/轻量级锁/重量级锁

  • 自旋锁

    自旋锁是采用让当前线程不停地的在循环体内执行实现的,当循环的条件被其他线程改变时 才能进入临界区
     可以参考:http://ifeve.com/java_lock_see1/

大家说到ReentrantLock这个锁,一般情况下第一个想法是它是一个可冲入锁,但是我认为另一个概念公平锁和非公平锁的实现更能体现出它的内涵:

//使用默认的非公平锁ReentrantLock nonFairReentrantLock = new ReentrantLock();//构造函数入参传true使用公平锁ReentrantLock fairReentrantLock = new ReentrantLock(true);

判断内容如下:

public ReentrantLock(boolean fair) {
 sync = fair ? new FairSync() : new NonfairSync();
}

从上边代码我们看到,通过构造函数中的一个布尔入参实现具体声明公平锁还是非公平锁。

众所周知ReentrantLock 底层是由AQS实现的,下图展示了AQS的链表结构:

以下是非公平锁的实现,在lock方法和tryAcquire方法中添加compareAndSetState方法,判断当前锁是否被占用,如果没有则当前线程会占用锁,
不会去判断队列中是否有队列是否在等待。以下是代码解释

static final class NonfairSync extends Sync {    private static final long serialVersionUID = 7316153563782823691L;    /**
   * Performs lock.  Try immediate barge, backing up to normal
   * acquire on failure.
   */
   final void lock() {        if (compareAndSetState(0, 1))
           setExclusiveOwnerThread(Thread.currentThread());        else
           acquire(1);
       }        protected final boolean tryAcquire(int acquires) {            return nonfairTryAcquire(acquires);
       }

   }    final boolean nonfairTryAcquire(int acquires) {        final Thread current = Thread.currentThread();        int c = getState();            if (c == 0) {                if (compareAndSetState(0, acquires)) {
                   setExclusiveOwnerThread(current);                    return true;
               }
           }            else if (current == getExclusiveOwnerThread()) {                int nextc = c + acquires;                if (nextc < 0) // overflow
                   throw new Error("Maximum lock count exceeded");
               setState(nextc);                return true;
           }            return false;
       }
   }
}

以下是公平锁,tryAcquire方法中判断了队列中的是否有线程等待。。

static final class FairSync extends Sync {    private static final long serialVersionUID = -3000897897090466540L;    final void lock() {
       acquire(1);
   }    /**
   * Fair version of tryAcquire.  Don't grant access unless
   * recursive call or no waiters or is first.
   */
   protected final boolean tryAcquire(int acquires) {        final Thread current = Thread.currentThread();        int c = getState();        if (c == 0) {            if (!hasQueuedPredecessors() &&
               compareAndSetState(0, acquires)) {
               setExclusiveOwnerThread(current);                return true;
           }
       }        else if (current == getExclusiveOwnerThread()) {            int nextc = c + acquires;            if (nextc < 0)                throw new Error("Maximum lock count exceeded");
           setState(nextc);            return true;
       }        return false;
   }
}

通过重入锁的公平锁与非公平锁的实现,我们看到是依赖于底层AQS来实现的,所以在这简单讲解一下AQS的原理

AQS定义两种资源共享方式:Exclusive(独占,只有一个线程执行)和share(共享,多个线程可同时执行,如Semaphore/CountDownLatch)

在这引用 waterystone博客中的两句总结:

以ReentrantLock为例,state初始化为0,表示未锁定状态。A线程lock()时,会调用tryAcquire()独占该锁并将state+1。
此后,其他线程再tryAcquire()时就会失败,直到A线程unlock()到state=0(即释放锁)为止,其它线程才有机会获取该锁。
当然,释放锁之前,A线程自己是可以重复获取此锁的(state会累加),这就是可重入的概念。但要注意,获取多少次就要释放多么次,这样才能保证state是能回到零态的。

再以CountDownLatch以例,任务分为N个子线程去执行,state也初始化为N(注意N要与线程个数一致)。这N个子线程是并行执行的,每个子线程执行完后countDown()一次,state会CAS减1。等到所有子线程都执行完后(即state=0),会unpark()主调用线程,然后主调用线程就会从await()函数返回,继续后余动作。

总结:ReentrantLock通过构造参数fair来判断是创建公平锁还是非公平锁,底层中的独享锁的实现以及队列等待功能依赖于AQS,
AQS是java中大部分锁的基础,其中可以划分独享和共享,根据volatile字段state实现可冲入。


  推荐站点

  • At-lib分类目录At-lib分类目录

    At-lib网站分类目录汇集全国所有高质量网站,是中国权威的中文网站分类目录,给站长提供免费网址目录提交收录和推荐最新最全的优秀网站大全是名站导航之家

    www.at-lib.cn
  • 中国链接目录中国链接目录

    中国链接目录简称链接目录,是收录优秀网站和淘宝网店的网站分类目录,为您提供优质的网址导航服务,也是网店进行收录推广,站长免费推广网站、加快百度收录、增加友情链接和网站外链的平台。

    www.cnlink.org
  • 35目录网35目录网

    35目录免费收录各类优秀网站,全力打造互动式网站目录,提供网站分类目录检索,关键字搜索功能。欢迎您向35目录推荐、提交优秀网站。

    www.35mulu.com
  • 就要爱网站目录就要爱网站目录

    就要爱网站目录,按主题和类别列出网站。所有提交的网站都经过人工审查,确保质量和无垃圾邮件的结果。

    www.912219.com
  • 伍佰目录伍佰目录

    伍佰网站目录免费收录各类优秀网站,全力打造互动式网站目录,提供网站分类目录检索,关键字搜索功能。欢迎您向伍佰目录推荐、提交优秀网站。

    www.wbwb.net