ReentrantLock之公平锁,可重入的理解

一.问题

ReentrantLock是jdk5里面的一个方法类,

主要讨论两个问题:

1.ReentrantLock的可重入体现

2.ReentrantLock的公平锁和非公平锁体现

二.讲解

2.1ReentrantLock的可重入体现

final boolean nonfairTryAcquire(int acquires) {  //这里我就跳过着讲解了,ReentrantLock模式使用的是非公平锁,这样能提高系统的响应性能
    final Thread current = Thread.currentThread();
    int c = getState();  //获取资源的状态,
    if (c == 0) {     //为0就是别人还没有获取到锁,这个时候当前线程就可以获取到锁
        if (compareAndSetState(0, acquires)) { //用cas的方式获取到锁
            setExclusiveOwnerThread(current);  //这个方法里面就只有这一句  exclusiveOwnerThread = thread; 设置当前线程是独占线程
            return true;
        }
    }
    else if (current == getExclusiveOwnerThread()) {   //重点来了,这个方法就是主要判断是不是可重入的,如果之前的判断资源的状态是被上锁了,就会执行到这里,如果判断是本线程
        int nextc = c + acquires;  //把资源的的请求次数加1
        if (nextc < 0) // 当然也不是可以不限加的,如果超出的int的范围,抛出一个error的错误
            throw new Error("Maximum lock count exceeded");
        setState(nextc);  //设置资源状态
        return true;
    }
    return false;
}
总结:ReentrantLock可重入主要体现在current == getExclusiveOwnerThread()这个判断方法上面。如果是当前重入线程,资源状态添加请求数,注意释放的时候也是要释放这个多次的。

2.2 ReentrantLock的公平锁和非公平锁体现

public ReentrantLock(boolean fair) {  //这个构造方法是用来生成公平锁和非公平锁的  fair=true 公平锁,false 非公平锁
    sync = fair ? new FairSync() : new NonfairSync();
}

补:公平锁:多个线程按fifo(先进先出)的顺序获取资源。典型的例子就是排队买票。

      非公平锁:多个线程不是按顺序获取资源的。典型的例子就是插队买票。

非公平锁的上锁过程

final void lock() {
    if (compareAndSetState(0, 1))    //如果当前这个线程可以用cas快获取得到资源的话,那就优先设置当前线程占用资源,这个是不管什么顺序的
        setExclusiveOwnerThread(Thread.currentThread());
    else
        acquire(1);  //快速设置资源失败,还是老老实实的去获取请求的资源吧  acquire 会调用nonfairTryAcquire方法
}
上面已经讲解了nonfairTryAcquire方法 ,这里不再重复讲解

公平锁的上锁过程

final void lock() {
    acquire(1);   //很简单 就是当前线程要一个资源
}
protected final boolean tryAcquire(int acquires) { //这里是公平锁的获取过程
        final Thread current = Thread.currentThread();  
        int c = getState();  //获取当前线程的状态,如果是0说明还没有别的线程占用资源
        if (c == 0) {
            if (!hasQueuedPredecessors() &&   //公平锁的重点,里面用了队列来实现锁,如果队列中第一个为空或者自己是第一个,就自己再去获取资源,如果有值了,就判断一个自己之前是不是已经获取过资源了,获取了就在重入一下,重入失败就返回false,表示获取资源失败
                compareAndSetState(0, acquires)) {  //下面和nonfairTryAcquire里面的一样,不做重复讲解
                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;
    }
}

线面来重点讲讲hasQueuedPredecessors()方法

public final boolean hasQueuedPredecessors() {  //这个方法用来判断是不是队列有前驱
    Node t = tail; // Read fields in reverse initialization order
    Node h = head;
    Node s;
    return h != t &&
        ((s = h.next) == null || s.thread != Thread.currentThread());   //队列不为空的情况下&&(队列中第一个有值||第一个线程不是自己)
}
!hasQueuedPredecessors()这样方法说人话的意思就是

  要么这个队列没有值,要么有值也就只能有我一个!

总结:公平锁的获取方式和非公平锁的获取方式有两点特殊的地方

    ①.公平锁不支持快速获取资源而非公平锁支持,(非公平锁获取到了,代码就不往下执行了,效率高于公平锁,这样的说服力够明显吧)

    ②.公平锁在获取资源的时候会判断当前AQS队列里面是不是有线程,还有就是当前线程要是获取资源的第一个。

       非公平锁就无所谓了,谁获取锁都行!

ReentrantLock的特性还有很多,未完后续再补...........
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值