ReentrantLock为例 AQS源码

AbstractQueuedSynchronizer 超详细原理解析

LockSupport

也位于包java.util.concurrent.locks下,基本方法↓

//当前线程放弃CPU,进入等待状态(WAITING),操作系统不再对它进行调度
public static void park()
//直到,有其他线程对它调用了unpark,指定它恢复
public static void unpark(Thread thread)

//指定时间的park变体
public static void parkNanos(long nanos)
public static void parkUntil(long deadline)

//返回线程的blocker对象
public static Object getBlocker(Thread t)

是怎么实现的呢?与CAS方法一样,它们也调用了Unsafe类中的对应方法,Unsafe类最终调用了操作系统的API,从程序员的角度,我们可以认为LockSupport中的这些方法就是基本操作
demo

import java.util.concurrent.locks.LockSupport;

public class LockSupportDemo {

    public static void main(String[] args) throws InterruptedException {
        Thread t = new Thread (){
            public void run(){
                    //本线程wait了
                LockSupport.park();
                System.out.println("exit");
            }
        };
        t.start();    
        Thread.sleep(1000);

            //把线程t恢复
        LockSupport.unpark(t);

    }

}

AQS (AbstractQueuedSynchronizer)

利用CAS和LockSupport提供的基本方法,就可以用来实现ReentrantLock了。但Java中还有很多其他并发工具,如ReentrantReadWriteLock、Semaphore、CountDownLatch,它们的实现有很多类似的地方,为了复用代码,Java提供了一个抽象类AbstractQueuedSynchronizer,我们简称为AQS,它简化了并发工具的实现。

1.提供了一个int 状态,供子类查询和设置

private volatile int state;

protected final int getState()
protected final void setState(int newState)
protected final boolean compareAndSetState(int expect, int update) 

2.当前(持有锁的)线程,提供了方法进行查询和设置

private transient Thread exclusiveOwnerThread;
protected final void setExclusiveOwnerThread(Thread t)
protected final Thread getExclusiveOwnerThread() 

3.内部维护了一个等待队列,无阻塞算法进行更新(借助CAS方法实现了)

ReentrantLock内部使用AQS,定义有三个内部类:

//继承AQS 的抽象类,不直接用 ,供后面2个继承
abstract static class Sync extends AbstractQueuedSynchronizer


static final class NonfairSync extends Sync//不公平
static final class FairSync extends Sync//公平

公平和不公平,选一个用,默认不公平↓

private final Sync sync;
//在构造方法中sync被赋值,默认不公平
public ReentrantLock() {
    sync = new NonfairSync();
}

ReentrantLock的lock方法

public void lock() {
    sync.lock();
}

NonfairSync的lock, 里面调用的都是父类AQS的方法

final void lock() {
    if (compareAndSetState(0, 1))
        //当前未被锁定,则立即获得锁
        setExclusiveOwnerThread(Thread.currentThread());
    else
        //否则调用acquire(1)获得锁
        acquire(1);
}

acquire是AQS中的方法,代码为:

public final void acquire(int arg) {
    if (!tryAcquire(arg) &&//这个方法必须被子类重写,AQS里面是抛出异常
//没有得到锁才会运行到&&后面
        acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
        selfInterrupt();
}

它调用tryAcquire获取锁,tryAcquire必须被子类重写,NonfairSync的实现为:

protected final boolean tryAcquire(int acquires) {
    return nonfairTryAcquire(acquires);
}

nonfairTryAcquire是sync中实现的,代码为:

final boolean nonfairTryAcquire(int acquires) {

    final Thread current = Thread.currentThread();
    int c = getState();
//如果未被锁定,则
    if (c == 0) {
        //使用CAS进行锁定
        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);
        //只要状态+1 其他什么都不用干
        return true;
    }
     //没拿到锁
    return false;
}

tryAcquire就是尝试获取那个线程独占的变量state.
state如果是0,那么当前还没有线程独占此变量;马上得到锁;
再进行一次判断,看是否是当前线程自己获得的这个锁,第二次进入锁,如果是,那么就增加state的值.否则,返回false

!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg)
如果tryAcquire返回false,则AQS会调用:
acquireQueued(addWaiter(Node.EXCLUSIVE), arg)
addWaiter会新建一个节点Node,代表当前线程,然后加入到等待队列尾部,

    private Node addWaiter(Node mode) {
        Node node = new Node(Thread.currentThread(), mode);
        //先使用快速入列法来尝试一下
        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();
//如果前区就是头了,再调一次tryAcquire尝试得到锁
            if (p == head && tryAcquire(arg)) {
//进这说明成功得到锁了
                setHead(node);
                p.next = null; // help GC
                failed = false;
                //返回中断标志
                return interrupted;
            }

//为了防止CPU不停的执行for循环,消耗CPU资源,
//暂时不可能得到锁就不要继续循环了,Park好了

            if (shouldParkAfterFailedAcquire(p, node) &&//是否要Park

                parkAndCheckInterrupt())//执行park
                //记录中断标志
                interrupted = true;
        }
    } finally {
        if (failed)
            cancelAcquire(node);
    }
}

//park
 private final boolean parkAndCheckInterrupt() {
        LockSupport.park(this); //将AQS对象自己传入
        return Thread.interrupted();
 }
 private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
        int ws = pred.waitStatus;
        if (ws == Node.SIGNAL) //前一个节点在等待独占性变量释放的通知,所以,当前节点可以阻塞
            return true;
        if (ws > 0) { //前一个节点处于取消获取独占性变量的状态,所以,可以跳过去,直到没有取消的一个前驱
            //返回false
            do {
                node.prev = pred = pred.prev;
            } while (pred.waitStatus > 0);
            pred.next = node;
        } else {
            //将上一个节点的状态设置为signal,返回false,
            compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
        }
        return false;
        }
public final void acquire(int arg) {
        if (!tryAcquire(arg) &&
//如果 boolean acquireQueued(final Node node, int arg) 返回true
//发生过中断
            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
            selfInterrupt();//发生中断才进这里
    }

调用selfInterrupt方法设置中断标志位,其代码为:

private static void selfInterrupt() {
    Thread.currentThread().interrupt();
}

能获得锁就立即获得,否则加入等待队列,
被唤醒后检查自己是否是第一个等待的线程,如果是且能获得锁,则返回,
否则继续等待,
这个过程中如果发生了中断,lock会记录中断标志位,
但不会提前返回或抛出异常。

你可能感兴趣的:(ReentrantLock为例 AQS源码)