Lock 接口出现之前,Java 程序是靠 synchronized 关键字实现锁功能的,而 Java SE 5之后,并发包中新增了 Lock 接口(以及相关实现类)用来实现锁功能,它提供了与synchronized 关键字类似的同步功能,只是在使用时需要显式地获取和释放锁。
Lock的简单使用:
Lock lock = new ReentrantLock();
lock.lock();
try {
} finally {
lock.unlock();
}
Lock的api:
Lock独占式获取锁lock()源码分析:
(1). 默认ReentrantLock()构建的是非公平锁对象,若要构建公平锁对象需要使用指定参数fair的构造方法创建。
public ReentrantLock() {
sync = new NonfairSync();
}
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}
(2). 公平同步器与非公平同步器均继承于父类Sync,分别实现了父类Sync的抽象方法lock(),以及重写了Sync的父类AbstractQueuedSynchronizer(抽象队列同步器)的方法tryAcquire(int acquires),lock()方法中调用的acquire(1)为AbstractQueuedSynchronizer的方法,区别在于acquire(1)的实现逻辑中调用的tryAcquire(int acquires)为各自的实现,因此,区别重点在于tryAcquire(int acquires)方法的区别上
static final class FairSync extends Sync {
private static final long serialVersionUID = -3000897897090466540L;
final void lock() {
acquire(1);
}
/**
* Fair version of tryAcquire. Don't grant access unless
* recursive call or no waiters or is first.
*/
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;
}
}
static final class NonfairSync extends Sync {
private static final long serialVersionUID = 7316153563782823691L;
/**
* Performs lock. Try immediate barge, backing up to normal
* acquire on failure.
*/
final void lock() {
if (compareAndSetState(0, 1)) // 直接获取同步状态,不判断队列数量以及节点顺序
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);
}
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires); // 该方法为父类Sync的方法,具体源码如下
}
}
// Sync的方法:
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;
}
(3). acquire(1)的实现源码,其为Sync的父类AbstractQueuedSynchronizer:
public final void acquire(int arg) {
if (!tryAcquire(arg) && // 为(2)中的各自实现方法
// 将节点加入到同步队列末端后开始自选,直到获取到同步状态后跳出自选,即获取到锁
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
// 获取同步状态失败后,将当前线程封装为Node,放入同步队列末端
private Node addWaiter(Node mode) {
Node node = new Node(Thread.currentThread(), mode);
// Try the fast path of enq; backup to full enq on failure
Node pred = tail;
if (pred != null) {
node.prev = pred;
if (compareAndSetTail(pred, node)) { // 使用compareAndSetTail将其节点放入队列末端
pred.next = node;
return node;
}
}
enq(node); // 将其节点放入队列末端直至成功
return node;
}
// 将其节点放入队列末端直至成功
private Node enq(final Node node) {
for (;;) {
Node t = tail;
if (t == null) { // Must initialize
if (compareAndSetHead(new Node()))
tail = head;
} else {
node.prev = t;
if (compareAndSetTail(t, node)) {
t.next = node;
return t;
}
}
}
}
// 自选获取同步状态
final boolean acquireQueued(final Node node, int arg) {
boolean failed = true;
try {
boolean interrupted = false;
for (;;) {
final Node p = node.predecessor(); // 获取当前节点的前一节点
// 判断前一节点是否为头节点,并尝试获取同步状态,而这里的tryAcquire(arg)为之前重写的方法,公平与非公平
if (p == head && tryAcquire(arg)) {
setHead(node);
p.next = null; // help GC
failed = false;
return interrupted;
}
// 检查线程是否中断,中断的话只修改中断状态,但是不影响继续获取同步状态,在外层selfInterrupt()进行自我中断
// 和可中断式获取区别在于此,可中断式直接抛出异常,终止获取同步状态,后面上源码
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
interrupted = true;
}
} finally {
if (failed)
cancelAcquire(node);
}
}
Lock可中断式获取锁lockInterruptibly()源码分析:
(1). ReentrantLock中的方法:
public void lockInterruptibly() throws InterruptedException {
// 这里的sync仍然为4中源码解析的构造器中的公平同步器或非公平同步器,其重要仍在于重写的
// tryAcquire(int acquires)
sync.acquireInterruptibly(1);
}
(2). acquireInterruptibly(1)方法源码,其为Sync的父类AbstractQueuedSynchronizer:
public final void acquireInterruptibly(int arg)
throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
if (!tryAcquire(arg))
doAcquireInterruptibly(arg);
}
private void doAcquireInterruptibly(int arg)
throws InterruptedException {
final Node node = addWaiter(Node.EXCLUSIVE);
boolean failed = true;
try {
for (;;) {
final Node p = node.predecessor();
// 此处tryAcquire(arg)仍为公平同步器与非公平同步器重写
if (p == head && tryAcquire(arg)) {
setHead(node);
p.next = null; // help GC
failed = false;
return;
}
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
// 与独占式同步器的区别在于此
throw new InterruptedException();
}
} finally {
if (failed)
cancelAcquire(node);
}
}
(3). 与lock()区别:
和lock()的区别在于:线程尝试获取锁操作失败后,在等待过程中,如果该线程被其他线程中断了,它是如何响应中断请求的。lock方法会忽略中断请求,继续获取锁直到成功;而lockInterruptibly则直接抛出中断异常来立即响应中断,由上层调用者处理中断
如果要求被中断线程不能参与锁的竞争操作,则此时应该使用lockInterruptibly方法,一旦检测到中断请求,立即返回不再参与锁的竞争并且取消锁获取操作(即finally中的cancelAcquire操作)
同步队列设置节点图解: