多线程与并发5 AQS源码分析、ThreadLocal源码

https://www.jianshu.com/p/497a8cfeef63// ReentrantLock构造函数传入了一个内部类 NonfairSync 

NonfairSync-》Sync-》AbstractQueuedSynchronizer 继承关系
public ReentrantLock() {
    sync = new NonfairSync();
}

//上锁也是调用NonfairSync 非公平锁
public void lock() {
    sync.lock();
}

//进入NonefairSync类的内部
final void lock() {
if (compareAndSetState(0, 1)) //获得锁 cas setExclusiveOwnerThread(Thread.currentThread()); else acquire(1); } protected final boolean compareAndSetState(int expect, int update) { // See below for intrinsics setup to support this return unsafe.compareAndSwapInt(this, stateOffset, expect, update); } stateOffset = unsafe.objectFieldOffset (AbstractQueuedSynchronizer.class.getDeclaredField("state"));
这里,对state的偏移量中的内存进行CAS操作,设置为1,表明第一次获取锁。AQS中,state是一个volatile变量,表示线程获取锁的次数,state为0,表示没有获取锁,state大于1,则表示重入锁获取的次数。执行完compareAndSetState第一次获取锁之后,执行setExclusiveOwnerThread,在AbstractOwnableSynchronizer类中设置成员变量Thread exclusiveOwnerThread为当前线程,表示这个线程独占了这个锁。
如果第二次调用lock()获取锁,由于内存中state不为0,cas失败,则进入else执行acquire(1);
public final void acquire(int arg) {
    if (!tryAcquire(arg) &&
        acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) //没有获得锁就acquireQueued 没有获得锁就放入队列中 cas放入队列末端
        selfInterrupt();
}
//tryAcquire是一个抽象方法,NonfairSync中的实现如下:
protected final boolean tryAcquire(int acquires) {
    return nonfairTryAcquire(acquires);
}

final boolean nonfairTryAcquire(int acquires) { 
    // 获取当前线程
    final Thread current = Thread.currentThread();
    // 得到state数量  state是一个用volatile修饰的整型数值  当获得锁之后会变成1 释放后又会变成0  有一个双向链表监控着这个state,里面全是线程。 
    int c = getState();
    // 没有获取过锁
    if (c == 0) {
        // 获取一次,cas设置state为acquires,也就是1
        if (compareAndSetState(0, acquires)) { //acquire(1)
            // 设置拥有者线程
            setExclusiveOwnerThread(current);
            return true;
        }
    }
    else if (current == getExclusiveOwnerThread()) {
        // 增加重入次数
        int nextc = c + acquires;
        if (nextc < 0) // overflow
            throw new Error("Maximum lock count exceeded");
        // 设置state,这里不需要同步,因为已经是统一线程第二次获取锁,也是在本线程里获取锁,没有线程安全问题,第一次调用的state和ownerThread一定是可见的
        setState(nextc);
        return true;
    }
    return false;
}
没有获得锁就acquireQueued 没有获得锁就放入队列中 cas操作放入队列末端。为什么是双向链表呢,因为需要知道前面节点的状态,前面线程持有锁,当前节点就尝试获得锁,如果获不到就阻塞,等待前置节节点释放后就叫醒后面的线程,否则阻塞。
  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);
        }
    }

猜你喜欢

转载自www.cnblogs.com/zdcsmart/p/12600740.html