前言
J.U.C
正文
Lock
Lock的出现可以解决Synchronized在某些场景中的短板,它比Synchronized更加灵活。
结构图
public interface Lock {
void lock();
void lockInterruptibly() throws InterruptedException;
boolean tryLock();
boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
void unlock();
Condition newCondition();
}
Lock是一个接口,其有多个实现,我们经常使用的是ReentrantLock,这里我们拿其举例说明,其他类似。
ReentrantLock有个内部抽象类Sync其继承了AbstractQueuedSynchronizer(AQS)这是其锁逻辑实现的核心,其有个被volatile修饰的state字段记录锁重入的次数,AQS的父类AbstractOwnableSynchronizer(AOS)记录被保存的线程。
Sync有两个具体的实现FairSync(公平锁),NonfairSync(非公平锁)。
ReentrantLock
锁都是可以重入的,我还没见过不可以重入的锁。
static Lock lock=new ReentrantLock(true);
public static void inc(){
lock.lock(); //获得锁(互斥锁) ThreadA 获得了锁
try {
Thread.sleep(1);
count++;
decr();
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
lock.unlock();//释放锁 ThreadA释放锁 state=1-1=0
}
}
public static void decr(){
lock.lock(); #state=2 //ThreadA再次来抢占锁 : 不需要再次抢占锁,而是只增加重入的次数
try{
count--;
}finally {
lock.unlock(); //state=1
}
}
lock() 加锁
public class ReentrantLock implements Lock, java.io.Serializable {
public ReentrantLock() {
sync = new NonfairSync();
}
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}
public void lock() {
sync.lock();
}
}
根据lock方法,找到内部类Sync的lock()
abstract static class Sync extends AbstractQueuedSynchronizer {
private static final long serialVersionUID = -5179523762034025860L;
abstract void lock();
}
根据ReentrantLock的构造方法可知,默认实现的是NonfairSync,我们直接进入对应实现的lock方法
static final class NonfairSync extends Sync {
private static final long serialVersionUID = 7316153563782823691L;
final void lock() {
if (compareAndSetState(0, 1)) //乐观锁
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);
}
}
这里是通过CAS乐观锁compareAndSetState去判断是否锁是否已被持有。
public abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer implements java.io.Serializable {
/**
* The synchronization state.
*/
private volatile int state;
protected final boolean compareAndSetState(int expect, int update) {
// See below for intrinsics setup to support this
return unsafe.compareAndSwapInt(this, stateOffset, expect, update);
}
}
由此可知通过被volatile修饰的state内存偏移量为0时为锁未被持有,然后设置当前线程为独占线程。
public abstract class AbstractOwnableSynchronizer implements java.io.Serializable {
private transient Thread exclusiveOwnerThread;
protected final void setExclusiveOwnerThread(Thread thread) {
exclusiveOwnerThread = thread;
}
}
如果没有抢占到锁呢
static final class NonfairSync extends Sync {
private static final long serialVersionUID = 7316153563782823691L;
final void lock() {
if (compareAndSetState(0, 1)) //乐观锁 这里保证只有一个线程进入
setExclusiveOwnerThread(Thread.currentThread()); //设置独占线程
else
acquire(1);
}
}
进入acquire(1)方法
public abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer implements java.io.Serializable {
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
}
这里有三个方法
- !tryAcquire(arg) :确认锁的状态,尝试去获取锁
static final class NonfairSync extends Sync {
private static final long serialVersionUID = 7316153563782823691L;
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
}
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; //state累加,增加重入次数
if (nextc < 0) // overflow
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
这里如果直接成功,就直接返回。
- addWaiter(Node.EXCLUSIVE) 将当前线程(未抢占到锁)存入双向链表(等待队列)中
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)) {
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;
}
}
}
}
- acquireQueued 抢占锁,或者阻塞
final boolean acquireQueued(final Node node, int arg) {
boolean failed = true;
try {
boolean interrupted = false;
for (;;) {
final Node p = node.predecessor(); //这里拿到当前节点的前一个节点
if (p == head && tryAcquire(arg)) { /如果前节点是头节点,这里会触发一次头节点抢占锁
setHead(node);
p.next = null; // help GC
failed = false;
return interrupted;
}
if (shouldParkAfterFailedAcquire(p, node) && //这里根据其前一个节点的状态判断是否需要挂起当前线程
parkAndCheckInterrupt())
interrupted = true; //返回加入队列成功
}
} finally {
if (failed)
cancelAcquire(node);
}
}
//这里是校验并改变前节点的状态
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
int ws = pred.waitStatus;
if (ws == Node.SIGNAL)
/*
* This node has already set status asking a release
* to signal it, so it can safely park.
*/
return true;
if (ws > 0) { //把取消状态的节点移除
do {
node.prev = pred = pred.prev;
} while (pred.waitStatus > 0);
pred.next = node;
} else { //
compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
}
return false;
}
private final boolean parkAndCheckInterrupt() {
LockSupport.park(this);
return Thread.interrupted();
}
unLock() 释放锁
public void unlock() {
sync.release(1);
}
public final boolean release(int arg) {
if (tryRelease(arg)) {
Node h = head;
if (h != null && h.waitStatus != 0)
unparkSuccessor(h);
return true;
}
return false;
}
private void unparkSuccessor(Node node) {
int ws = node.waitStatus;
if (ws < 0)
compareAndSetWaitStatus(node, ws, 0);
Node s = node.next;
if (s == null || s.waitStatus > 0) {
s = null;
for (Node t = tail; t != null && t != node; t = t.prev)
if (t.waitStatus <= 0)
s = t;
}
if (s != null)
LockSupport.unpark(s.thread);
}
将锁的重入次数-1,在链表中移除当前节点,并unPark当前节点的next节点的线程,然后这个释放的节点就会进行自旋去抢占锁。
总结
- lock的存储结构:一个int类型状态值(用于锁的状态变更),一个双向链表(用于存储等待中的线程)
- lock获取锁的过程:本质上是通过CAS来获取状态值修改,如果当场没获取到,会将该线程放在线程等待链表中。
- lock释放锁的过程:修改状态值,调整等待链表。