深入理解ReentrantLock

概念

ReentrantLock是一种可重入锁,即一个线程可以对同一个资源反复的加锁。同时,该锁还可以设置公平与非公平。公平锁是按线程的到达顺序进行获取锁操作,而非公平锁是抢占式。所以公平锁的效率是没有非公平锁高的,但是公平锁可以减少“线程饥饿”发生概率。

与syncchronized的比较

synchronized:是一种同步锁,串行锁,他是基于jvm实现的,通过montionentr指令加锁,monitionexit指令解锁。是一种隐式的可重入锁。而且无法中断一个在等待的线程
reentrantlock:是基于Java代码实现的,可重入,可以中断正在等待的线程。

使用场景

用在界面交互时点击执行较长时间请求操作时,防止多次点击导致后台重复执行(忽略重复触发)。

比如说在安卓中,转到native页面时由于网络慢可能要等待一下,这是候用户可能会反复点击,如果不加重入锁等网络通畅时将产生无数个native界面,有可能使APP内存爆掉。

在concurrentHashmap就是通过用reentrantlock来锁segment,实现锁分段的。

优缺点

优点:可重入,可以使用conditon进行灵活的控制
缺点:必须在finilly中释放

源码分析

reentrantlock实现了lock接口

public class ReentrantLock implements Lock, java.io.Serializable

里面通过sync这个抽象静态类实现加锁解锁,默认锁是非公平的

abstract static class Sync extends AbstractQueuedSynchronizer{
    final boolean nonfairTryAcquire(int acquires){...}
    protected final boolean tryRelease(int releases){...};
    .......
}

Sync这个类只是一个基类,通过nofairsync与fairsync继承sync来实现非公平锁与公平锁

static final class NonfairSync extends Sync {
        private static final long serialVersionUID = 7316153563782823691L;
        protected final boolean tryAcquire(int acquires) {
            return nonfairTryAcquire(acquires);
        }
    } //非公平锁加锁解锁直接使用的就是sync的方法

fairsync公平锁

static final class FairSync extends Sync {
        @ReservedStackAccess
        protected final boolean tryAcquire(int acquires) {
            ......//重行实现了tryAcquire
        }
    }

好了,下面我们来看一下非公平锁的加锁方法「不公平的加锁方法,如果state为0,则使用原子操作更新state,然后设置当前锁的拥有者为当前线程」

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;
        }

在看一下公平的加锁方法「比不公平加锁多了一步判断【hasQueuedPredecessors(),这个函数是判断阻塞队列里面当前线程前面是否有等待的线程,有的话就让前面的先获取锁】然后与上面非公平的一样

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;
        }

解锁操作公平与非公平都是一样的,当state为0时,free = true 将当前锁占有者线程设为null「setExclusiveOwnerThread(null)」;只有当state为0才能释放,如果state != 0 ,free=flase,返回free

protected final boolean tryRelease(int releases) {
            int c = getState() - releases;
            if (Thread.currentThread() != getExclusiveOwnerThread())
                throw new IllegalMonitorStateException();
            boolean free = false;
            if (c == 0) {
                free = true;
                setExclusiveOwnerThread(null);
            }
            setState(c);
            return free;
        }

reentrantlock默认是非公平的

public ReentrantLock() {
        sync = new NonfairSync();
    }

reentrantlock构造函数传入fair以设置公平

public ReentrantLock(boolean fair) {
        sync = fair ? new FairSync() : new NonfairSync();
    }
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值