JUC之ReentrantLock

对着背影说爱祢 提交于 2019-11-26 14:32:44

JUC之ReentrantLock

一、什么是ReentrantLock

ReentrantLock就是可重入锁,它主要实现了以下两种机制:

  • 可重入,一个线程可以重复获取该锁。
  • 公平性,它实现了公平锁与非公平锁。
    • 前者能够解决饥饿问题,但是会耗费进百倍的性能
    • 后者可能会造成饥饿问题,但是,性能更好。
  • 可重入锁,它本身是一个独占锁。

二、ReentrantLock的实现

1、重入机制的实现

  • 解决重入问题
protected final boolean tryAcquire(int acquires) {
    final Thread current = Thread.currentThread();
    int c = getState();
  //计数为0,无需解决重入问题,直接CAS获取
    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;
}
  • 解决重入释放问题
protected final boolean tryRelease(int releases) {
    int c = getState() - releases;
    if (Thread.currentThread() != getExclusiveOwnerThread())
        throw new IllegalMonitorStateException();
    boolean free = false;
  //重入N次,知道释放N次,才返回true,否则一直都是false;
    if (c == 0) {
        free = true;
        setExclusiveOwnerThread(null);
    }
    setState(c);
    return free;
}

2、公平机制的实现

  • fair
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;
}
  • unfair
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;
}

三、ReentrantLock的应用

在java中,基本上所有的锁都是可重入锁,因为可重入锁本身就是为了避免死锁问题,死锁从某种意义上讲是一种错误的行为,为了纠正这种行为,所有的锁都设计成可重入锁。以下是重入锁的一些应用:

  • ReentrantReadWriteLock
    • ReadLock
    • WriteLock
  • CyclicBarrier
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!