zoukankan      html  css  js  c++  java
  • ReentrantLock详解

    ReentrantLock概述

    ReentrantLock是Lock接口的实现类,可以手动的对某一段进行加锁。ReentrantLock可重入锁,具有可重入性,并且支持可中断锁。其内部对锁的控制有两种实现,一种为公平锁,另一种为非公平锁。ReentrantLock的实现原理为volatile+CAS

    ReentrantLock可重入性

    ReentrantLock具有可重入性,可重入性是指当一个线程拥有一个方法的锁以后,是否还可以进入该方法,一般这种情况出现在递归中。ReentrantLock的可重入性是基于Thread.currentThread()实现的,是线程粒度的,也就是说当前线程获得一个锁以后,当前线程的所有方法都可以获得这个锁。Reentrant依赖的锁只有两种实现类,NonFairSyncFairSync,但是它们获取锁的方式大同小异。一下是公平锁的获取实现。ReentrantLock.FairSync.tryAcquire

     1 protected final boolean tryAcquire(int acquires) {
     2             final Thread current = Thread.currentThread();
     3             int c = getState();
     4             //每一次加锁state+1
     5             if (c == 0) {
     6                 if (!hasQueuedPredecessors() &&
     7                     compareAndSetState(0, acquires)) {
     8                     setExclusiveOwnerThread(current);
     9                     return true;
    10                   //尝试获取锁成功
    11                 }
    12             }
    13             //是当前线程直接取到到锁,实现锁的可重入
    14             else if (current == getExclusiveOwnerThread()) {
    15                 int nextc = c + acquires;
    16                 if (nextc < 0)
    17                     throw new Error("Maximum lock count exceeded");
    18                 setState(nextc);
    19                 return true;
    20             }
    21             return false;
    22         }
    23     }    

    ReentrantLock锁的实现分析

    ReentrantLock有两种锁的实现,FairSyncNonFairSync,对于这两种锁,他们获取锁的方式都大同小异ReentrantLock$Sync#acquire

    1    public final void acquire(int arg) {
    2         //通过tryAcquire去尝试获取锁,公平锁和非公平锁有不同的实现
    3         if (!tryAcquire(arg) &&
    4         //如果没有获取到,就将该线程加入等待队列,然后循环尝试获取该锁
    5             acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
    6         //如果尝试获取锁的次数达到一定次数,就会触发中断,中断该线程,并释放锁
    7             selfInterrupt();
    8     }

    tryAcquire():尝试获取锁;

    addWaiter():将线程加入等待队列

    acquireQueued():在多次循环中尝试获取到锁或者将当前线程堵塞

    selfInterrupt():如果多次未获取成功,将中断该线程(避免死锁)

    公平锁(FairSync)

    公平锁内部维护了一个等待获取该锁的线程的队列,会按照队列顺序给每个线程锁。每当抢占锁的时候,就会判断是否有等待队列,如果有等待队列,就从等待队列的头开始分配锁

     1         protected final boolean tryAcquire(int acquires) {
     2             //取得当前请求锁的线程
     3             final Thread current = Thread.currentThread();
     4            //取得stage,每一次加锁,stage都会+1,如果stage是0,就说明,没有人使用该锁
     5             int c = getState();
     6             if (c == 0) {
     7                 //如果没有等待队列,并且CAS通过,就将当前线程就抢到了锁
     8                 if (!hasQueuedPredecessors() &&
     9                     compareAndSetState(0, acquires)) {
    10                     setExclusiveOwnerThread(current);
    11                     return true;
    12                 }
    13             }
    14             //如果锁没有释放,就判断当前线程是否是该锁的拥有者,如果是,可以直接使用该改,并stage+1
    15             else if (current == getExclusiveOwnerThread()) {
    16                 int nextc = c + acquires;
    17                 if (nextc < 0)
    18                     throw new Error("Maximum lock count exceeded");
    19                 setState(nextc);
    20                 return true;
    21             }
    22             //如果没有抢到锁,就返回false
    23             return false;
    24         }
    View Code

    非公平锁(NonFairSync)

    非公平锁在抢占锁时,会进行随机抢占,后抢占的线程往往抢占到的几率比较大。

    1 if (c == 0) {
    2                 //非公平锁仅仅是使用CAS,并不会去查看队列(也没有队列)
    3                 if (compareAndSetState(0, acquires)) {
    4                     setExclusiveOwnerThread(current);
    5                     return true;
    6                 }
    7             }

    ReentrantLock的内存可见性

    ReentrantLock保证内存可见性,作用和synchronized一样,但是要比synchronized更加灵活,方便,ReentrantLock可以和Condition联合使用

  • 相关阅读:
    jqGrid详解及高级应用(十四)
    ERP存储过程的调用和树形菜单的加载(四)
    IDisposable接口
    SQL调用系统存储过程整理
    Net作业调度-----Quartz.Net
    C#泛型(二)
    ERP通用存储过程封装(三)
    ERP PowerDesigner工具使用(二)
    ERP简介(一)
    jQuery.TreeView插件实现树状导航(十三)
  • 原文地址:https://www.cnblogs.com/duodushuduokanbao/p/9531773.html
Copyright © 2011-2022 走看看