JAVA并发编程-从ReentrantLock看AQS实现源码解读

ReentrantLock的构造方法
	//默认非公平锁
    public ReentrantLock() {
        sync = new NonfairSync();
    }
    //指定
    public ReentrantLock(boolean fair) {
        sync = fair ? new FairSync() : new NonfairSync();
    }
    
ReentrantLock的加锁流程

JAVA并发编程-从ReentrantLock看AQS实现源码解读_第1张图片

  • 执行ReentrantLock的lock方法
public void lock() {
   //这里自己实现了一个内部类
   sync.lock();
}
  • 这里也默认的非公平锁举例
	abstract static class Sync extends AbstractQueuedSynchronizer {
		//...省略部分代码
        abstract void lock();
		//...省略部分代码
    }
    //非公平锁的实现方式,也默认使用的
    static final class NonfairSync extends Sync {

        final void lock() {
        	//上来就先基于CAS的方式,尝试将state从0改为1
            if (compareAndSetState(0, 1))
            	//获取锁资源成功,会将当前线程设置到exclusiveOwnerThread属性,代表是当前线程持有着锁资源
                setExclusiveOwnerThread(Thread.currentThread());
            else
            	//调用AQS里面的acquire方法
                acquire(1);
        }
		//...省略部分代码
    } 
  • 调用AQS里面的acquire方法
	//aqs的模板方法
   public final void acquire(int arg) {
   	//tryAcquire aqs不实现,reentrantLock实现
       if (!tryAcquire(arg) &&
           	//1.没有拿到锁资源
           	//2.addWaiter(Node.EXCLUSIVE)将当前线程封装为node节点放到双向链表尾端,并制定模式是独占模式
           	// acquireQueued:查看我是否是第一个排队的节点,如果是可以再次尝试获取锁资源,如果长时间拿不到,挂起线程
       // 如果不是第一个排队的额节点,就尝试挂起线程
           acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
           //中断线程
           selfInterrupt();
   }

   static final class NonfairSync extends Sync {
   			//...省略部分代码
   			protected final boolean tryAcquire(int acquires) {
   			//又调用了父类Sync中nonfairTryAcquire
   			return nonfairTryAcquire(acquires);
   	    }
   }
   
   abstract static class Sync extends AbstractQueuedSynchronizer {

   		//...省略部分代码
   		//非公平方式获取锁
   		final boolean nonfairTryAcquire(int acquires) {
   			final Thread current = Thread.currentThread();
   			int c = getState();
   			if (c == 0) {
   				//获取state如果是0,代表没有线程获取这把锁,通过cas获取锁
   				if (compareAndSetState(0, acquires)) {
   					//设置当前所有者
   					setExclusiveOwnerThread(current);
   					return true;
   				}
   			}
   			else if (current == getExclusiveOwnerThread()) {
   				//当前持有锁的线程是自己则state+1;即实现可重入
   				int nextc = c + acquires;
   				if (nextc < 0) // overflow
   				//超过int最大值
   					throw new Error("Maximum lock count exceeded");
   				setState(nextc);
   				return true;
   			}
   			return false;
   		}
   			//...省略部分代码
   	}
  
}
   
  • 当前线程尝试一次没有获取到锁资源需要到AQS队列中去排队
private Node addWaiter(Node mode) {
        Node node = new Node(Thread.currentThread(), mode);
        // 把当前线程分装为node对象,并通过cas方式放到队列尾端
        Node pred = tail;
        if (pred != null) {
            node.prev = pred;
            if (compareAndSetTail(pred, node)) {
                pred.next = node;
                return node;
            }
        }
        //如果一次cas方式失败了,以死循环的方式,保证当前线程的Node一定可以放到AQS队列的末尾
        enq(node);
        return node;
    }
private Node enq(final Node node) {
		//通过死循环的方式放到	aqs双向链表尾部
        for (;;) {
            Node t = tail;
            if (t == null) { // 链表初始化
                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 (;;) {
            	//获取node的前一个节点
                final Node p = node.predecessor();
                //如果node的前一个节点是头节点,那么尝试获取锁
                if (p == head && tryAcquire(arg)) {
                	//设置当前节点为新的头节点
                    setHead(node);
                    //防止内存泄漏,让p.next可以被回收
                    p.next = null; // help GC
                    failed = false;
                    return interrupted;
                }
                //shouldParkAfterFailedAcquire:基于上一个节点转改来判断当前节点是否能够挂起线程,如果可以返回true,
            	// 如果不能,就返回false,继续下次循环
                if (shouldParkAfterFailedAcquire(p, node) &&
                    parkAndCheckInterrupt())
                    // 这里基于Unsafe类的park方法,将当前线程挂起
                    interrupted = true;
            }
        } finally {
            if (failed)
            	//在lock()方法中基本不执行
                cancelAcquire(node);
        }
    }
// 当前Node没有拿到锁资源,或者没有资格竞争锁资源,看一下能否挂起当前线程
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
		// -1,SIGNAL状态:代表当前节点的后继节点,可以挂起线程,后续我会唤醒我的后继节点
    	// 1,CANCELLED状态:代表当前节点以及取消了
        int ws = pred.waitStatus;
        if (ws == Node.SIGNAL)
            return true;
        if (ws > 0) {
            do {
            	//1.链表移除当前pred节点,以pred的前一个节点作为新的pred
            	//2.循环1.直到状态小于0
                node.prev = pred = pred.prev;
            } while (pred.waitStatus > 0);
            pred.next = node;
        } else {
        	//将上一个节点的状态改为-1
            compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
        }
        return false;
    }

    private final boolean parkAndCheckInterrupt() {
    	//阻塞当前线程
        LockSupport.park(this);
        //返回中断状态
        return Thread.interrupted();
    }
ReentrantLock的释放锁流程

JAVA并发编程-从ReentrantLock看AQS实现源码解读_第2张图片

  • 执行ReentrantLock的unlock方法
    public void unlock() {
        sync.release(1);
    }
    //释放锁的核心流程
    public final boolean release(int arg) {
        if (tryRelease(arg)) {
            Node h = head;
            //如果头节点不为null,并且状态不是0是-1,说明后面有排队的node
            if (h != null && h.waitStatus != 0)
            	//唤醒排队的线程
                unparkSuccessor(h);
            return true;
        }
        return false;
    }
    //释放锁流程
     abstract static class Sync extends AbstractQueuedSynchronizer {
		//...省略部分代码
        protected final boolean tryRelease(int releases) {
            int c = getState() - releases;
            if (Thread.currentThread() != getExclusiveOwnerThread())
            	//如果当前线程没有持有这把锁,抛异常	
                throw new IllegalMonitorStateException();
            //free,代表当前锁资源是否释放干净了。
            boolean free = false;
            if (c == 0) {
            	//锁资源释放完
                free = true;
                setExclusiveOwnerThread(null);
            }
            setState(c);
            return free;
        }
        //...省略部分代码
    }
    //唤醒后继阻塞线程    
	private void unparkSuccessor(Node node) {

        int ws = node.waitStatus;
        if (ws < 0)
        	// 先基于CAS,将节点状态从-1,改为0
            compareAndSetWaitStatus(node, ws, 0);
        Node s = node.next;
        // 如果后续节点为null或者,后续节点的状态为1,代表节点取消了。
        if (s == null || s.waitStatus > 0) {
            s = null;
            //从后往前依次找到状态小于等于0,并且离head最近的节点
            for (Node t = tail; t != null && t != node; t = t.prev)
                if (t.waitStatus <= 0)
                    s = t;
        }
        if (s != null)
        	//执行unpark唤醒
            LockSupport.unpark(s.thread);
    }

    

你可能感兴趣的:(并发编程,java,数据结构,链表,jvm)