锁之ReentrantLock
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了锁之ReentrantLock相关的知识,希望对你有一定的参考价值。
源码结构图
Lock源码
public interface Lock {
//获取锁
void lock();
/**
*当前线程的锁没有中断才能获取锁
* if (Thread.interrupted())
* throw new InterruptedException();
*/
void lockInterruptibly() throws InterruptedException;
//获取锁是否成功。true表示获取到锁,false表示没有获取到锁
boolean tryLock();
// 尝试获取锁,并等待指定的时间
boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
// 释放锁
void unlock();
// LOCK条件
Condition newCondition();
}
ReentrantLock源码
public class ReentrantLock implements Lock, java.io.Serializable {
// 同步器,是整个锁机制的实现者
private final Sync sync;
// 定义的抽象静态内部类。实现基本的功能
abstract static class Sync extends AbstractQueuedSynchronizer {
// 抽象方法。由公平锁和非公平锁自己实现
abstract void lock();
// 释放锁
protected final boolean tryRelease(int releases) {
// 锁的计数器。释放一次计数器减1,直到为0,则整个锁完全释放,才能被其他线程获取该锁。
int c = getState() - releases;
// 此类型锁是可重入锁。因此是以thread为粒度的。必须判断当前线程是否与持有锁线程一致。
if (Thread.currentThread() != getExclusiveOwnerThread())
throw new IllegalMonitorStateException();
boolean free = false;
// 当锁的计数器为0时,整个锁释放。
if (c == 0) {
free = true;
setExclusiveOwnerThread(null);
}
setState(c);
return free;
}
// 默认实现的一个非公平锁的获取尝试获取方法
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
// 如果锁的计数器为0,则表示没有锁。
if (c == 0) {
// compareAndSetState方法实际调用的是unsafe.compareAndSwapInt(this, stateOffset, expect, update);
// 直接操作的JVM。并给当前线程持有锁。
if (compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
// 如果计数器不为0,但当前线程就是持有锁的线程。则锁的计数器增加。
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < 0) // overflow
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
// 如果计数器不为0,同时当前线程不是持有锁的线程。则加锁失败。
return false;
}
}
// 非公平所的实现器
static final class NonfairSync extends Sync {
// 加锁。
final void lock() {
if (compareAndSetState(0, 1)) //非公平加锁
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1); // 如果加锁不成功,则放入队列
}
// 试着加锁
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
}
// 公平锁
static final class FairSync extends Sync {
// 加锁,队列
final void lock() {
acquire(1);
}
// 试着加锁
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;
}
}
}
AbstractQueuedSynchronizer源码
// 存储队列锁的存储node.是一个双向的链表结构。
static final class Node {
// 前一个node
volatile Node prev;
// 后一个node
volatile Node next;
// 该node所对应的线程
volatile Thread thread;
}
// 整个队列锁的第一个node.
private transient volatile Node head;
// 整个队列锁的第后个node.
private transient volatile Node tail;
// 锁的状态。计数器
private volatile int state;
// 加锁的关键点。通过navtive 方法unsafe直接操作CPU。
protected final boolean compareAndSetState(int expect, int update) {
return unsafe.compareAndSwapInt(this, stateOffset, expect, update);
}
总结
Lock这种以类的方式来实现锁的机制。
优点:
1.加锁和释放锁独立,可以分开来控制。
2.tryLock的方法可以尝试加锁,不会像sychnorized一致阻塞。
3.实现了公平锁和非公平锁。sychnorized只能是非公平锁。
缺点:
1.增加了代码的复杂度。
2.相比sychnorized的自动加锁和释放锁,Lock需要手动,容易忘记,从而出现重大的隐患。
经过JDK的不断更新,sychnorized与lock的性能相差不大,官方建议使用sychnorized方法加锁。
以上是关于锁之ReentrantLock的主要内容,如果未能解决你的问题,请参考以下文章