重入锁--ReentrantLock

来源:互联网 发布:怎么修改远程桌面端口 编辑:程序博客网 时间:2024/05/01 09:57

重入锁,支持冲进入的锁,表示该锁能够支持一个线程对资源的重复加锁。同时,该锁还支持获取锁时的公平和非公平性选择

实现

重进入是指任意线程在获取到锁之后能够再次获取该锁而不会被锁所阻塞。该特性的实现需要解决下面两个问题

1. 线程再次获取锁。锁需要去识别获取锁的线程是否为当前占据锁的线程,如果是,则再次获取成功

2. 锁的最终释放。线程重复n次获取锁,随后在第n次释放该锁后,其他线程能够获取到该锁。锁的最终释放要求锁对于获取进行计数自增,计数表示当前锁被重复获取的次数,而被释放时,计数自减,当技术等于0时,表示锁已完全被释放

ReentrantLock是通过组合自定义同步器来实现锁的获取与释放,以非公平性(默认的)实现为例:

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

该方法增加了再次获取同步状态的处理逻辑:通过判断当前线程是否为获取锁的线程来决定获取操作是否成功,如果是获取锁的线程再次请求,则将同步状态只进行增加并返回true。成功获取锁的线程再次获取锁,只是增加了同步状态值,从而要求ReentrantLock在释放同步状态时减少同步状态值。

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

该方法将同步状态是否为0作为最终释放的条件,当同步状态为0时,将占有线程设置为null,并返回true,表示释放成功。

公平与非公平获取锁的区别

如果一个锁是公平的,那么锁的获取顺序就应该符合FIFO。公平锁的获取代码如下:

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

公平获取与非公平获取的代码对比,就是在判断条件多了hasQueuedPredecessors() ,即加入了同步队列中当前节点是否有前驱节点的判断,如果该方法返回true,则表示有线程比当前线程更早得请求获取锁,因此需要等待前驱线程获取并释放锁后才能继续获取锁。

非公平锁虽然会引起“饥饿”,但是开销要更小,因此是默认的实现。

0 0
原创粉丝点击