您好,欢迎来到站长目录(28sn.com)!


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

来源:网络整理 浏览:347次 时间:2022-09-30
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实现可冲入。


推荐站点

  • 我爱发烧音乐我爱发烧音乐

    我爱发烧音乐囊括了从流行音乐到古典音乐多个类型的音乐作品,专栏推荐最新的音乐,提供音乐排名榜单!可供免费线上收听音乐,歌曲流畅,音效极佳! 网站提供的钢琴以及二胡专栏,可供收听者,陶冶情操,改善心情,是难得的轻音乐典藏!

    www.520fs.com
  • 世纪音乐网世纪音乐网

    世纪音乐网是专业的在线音乐试听MP3下载网站。歌曲总计30余万首,收录了网上最新歌曲和流行音乐,DJ舞曲,非主流音乐,经典老歌,劲舞团歌曲,搞笑歌曲,儿童歌曲,英文歌曲等。是您上网听歌的最佳网站。

    www.ssjj.com
  • 杭州网杭州网

      杭州网是杭州地区唯一的新闻门户网站,由中共杭州市委宣传部、杭州日报报业集团和杭州广播电视集团共同组建的杭州网络传媒有限公司运营。

    www.hangzhou.com.cn
  • 深圳在线深圳在线

      深圳在线 www.szol.net是深圳本地最大、最早的地方生活资讯网站之一,网站名“深圳在线www.szol.net”由南方报业传媒集团编辑委员会总编辑、南方日报社总编辑、南方都市报总编辑、南方书画院名誉院长王春芙亲笔题名,深圳在线www.szol.net团队与深圳热线www.szonline.net、奥一网www.oeeee.com都源于全国最早成立于1996年的知名网络公司——深圳万用网。

    www.szol.net
  • 今题网今题网

     今题网- 中国领先的社区服务网,提供社区服务, 在线交友和商家推广服务,于2004年创建上线,公司现有员工超过百名。今题网自成立以来,凭借其独特的定位和丰富的社区交友功能, 凭借其团队超强的搜索引擎优化技术吸引超过千万的用户成为今题网的注册会员。

    www.jinti.com

鄂公网安备 42062502000001号