JDK1.5之前只能利用synchronized实现线程同步,JDK1.5之后开始借助JNI来完成更高级的锁。
JDK 5中的锁是接口java.util.concurrent.locks.Lock,并提供了相应的实现类java.util.concurrent.locks.ReentrantLock
1 举栗子
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class AtomicIntegerWithLock {
private int value;
private Lock lock = new ReentrantLock();
public AtomicIntegerWithLock() {
super();
}
public AtomicIntegerWithLock(int value) {
this.value = value;
}
public final int get() {
lock.lock();
try {
return value;
} finally {
lock.unlock();
}
}
public final void set(int newValue) {
lock.lock();
try {
value = newValue;
} finally {
lock.unlock();
}
}
}
2 ReentrantLock源码解析
按照老规矩,按使用顺序分析
Lock lock = new ReentrantLock();
lock.lock();
...
lock.unlock();
(1)ReentrantLock
public ReentrantLock() {
sync = new NonfairSync();
}
public void lock() {
sync.lock();
}
从这里可以看出ReentrantLock使用的是非公平锁NonfairSync,所以我们来看看NonfairSync的lock方法
(2)NonfairSync(ReentrantLock内部类)
static final class NonfairSync extends Sync {
final void lock() {
//compareAndSetState(0, 1)用来尝试获取锁,如果能获取,则将state状态从0改为1,并返回true
if (compareAndSetState(0, 1))
//如果为true,则将获取锁的线程设置为当前线程
setExclusiveOwnerThread(Thread.currentThread());
else
//如果为false,则再次尝试获取锁,成功则直接返回,失败则加入等待队列,并禁用当前线程
acquire(1);
}
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
}
NonfairSync 继承自Sync,Sync继承AbstractQueuedSynchronizer(AQS)
lock中三个重要的方法compareAndSetState(0, 1),setExclusiveOwnerThread,acquire,这三个方法最终的实现都在AbstractQueuedSynchronizer(AQS)
所以接下来重点看AQS
(3)Sync(ReentrantLock内部类)
abstract static class Sync extends AbstractQueuedSynchronizer {
abstract void lock();
......
}
(4)AbstractQueuedSynchronizer
我们先来看compareAndSetState(0, 1),compareAndSetState用来尝试获取锁,如果能获取,则将state状态从0改为1,并返回true,这时将获取锁的线程设置为当前线程
/**
* @param expect the expected value
* @param update the new value
*/
protected final boolean compareAndSetState(int expect, int update) {
return U.compareAndSwapInt(this, STATE, expect, update);
}
这里U是Unsafe类
private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
所以调用到了Unsafe中的compareAndSwapInt,而compareAndSwapInt是一个Native方法
再来看看setExclusiveOwnerThread(Thread.currentThread());
protected final void setExclusiveOwnerThread(Thread thread) {
exclusiveOwnerThread = thread;
}
然后是acquire(1),加锁失败后进入acquire再次尝试获取锁,如果尝试成功(tryAcquire(arg)==true)则直接返回(&&的短路效果),否则将当前线程加入锁的等待队列(acquireQueued(addWaiter(Node.EXCLUSIVE), arg)))并禁用当前线程
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
acquire首先调用tryAcquire
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
//如果当前state==0,表示没有锁竞争,会再尝试获取锁
if (c == 0) {
if (compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
//如果current== getExclusiveOwnerThread,表示当前线程已经获取锁了,锁的记数+1
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;
}
从上可以看出在state==0和current == getExclusiveOwnerThread()的情况下,tryAcquire返回true
如果tryAcquire没有成功,就继续执行acquireQueued(addWaiter(Node.EXCLUSIVE), arg),其中Node.EXCLUSIVE==null,arg==1
private Node addWaiter(Node mode) {
Node node = new Node(mode);
for (;;) {
Node oldTail = tail;
if (oldTail != null) {
U.putObject(node, Node.PREV, oldTail);
if (compareAndSetTail(oldTail, node)) {
oldTail.next = node;
return node;
}
} else {
initializeSyncQueue();
}
}
}
addWaiter将线程和线程的状态信息封装到node对象中,然后将node添加到链表尾部,再来看acquireQueued
final boolean acquireQueued(final Node node, int arg) {
try {
boolean interrupted = false;
for (;;) {
// 如果当前线程是head的直接后继则尝试获取锁
// 这里不会和等待队列中其它线程发生竞争,但会和尝试获取锁且尚未进入等待队列的线程发生竞争。这是非公平锁和公平锁的一个重要区别。
final Node p = node.predecessor();
if (p == head && tryAcquire(arg)) {
setHead(node);
p.next = null; // help GC
return interrupted;
}
// 如果不是head直接后继或获取锁失败,则检查是否要禁用当前线程
// 是则禁用,直到被lock.release唤醒或线程中断
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
interrupted = true;
}
} catch (Throwable t) {
cancelAcquire(node);
throw t;
}
}
acquireQueued是个无限循环.就是说要么获取到锁,要么中断当前线程. acquireQueued会再次调用tryAcquire,就是再尝试一次获取锁. shouldParkAfterFailedAcquire判断是否要中断当前线程
3 总结
(1)ReentrantLock.lock()
如果该锁没有被另一个线程保持,则获取该锁并立即返回,将锁的保持计数设置为 1
如果当前线程已经保持该锁,则将保持计数加 1,并且该方法立即返回
如果该锁被另一个线程保持,则出于线程调度的目的,禁用当前线程,并且在获得锁之前,该线程将一直处于休眠状态,此时锁保持计数被设置为 1
(2)公平锁和非公平锁
如果获取一个锁是按照请求的顺序得到的,那么就是公平锁,否则就是非公平锁