Notes on ReentrantLock distribution of JAVA source code

After reading for a few days, I couldn't come up with anything. I took the jdk source code and found out the price and comments, and memorized the eight-part essay.

tryAcquire
线程5 设置state=1,直接执行,其他线程acquire(1)
其他线程获取state不等0,返回false,执行addWaiter,获取到同线程5

- 公平锁 判断state==0并且 前面没有人排队,才会cas
	- 如果前面有排队,失败执行后面的入队操作
	头尾节点都为空或者头尾节点同一个表示不同排队(可能此时有其他线程,但是不要紧,后面还是尝试获取)
	第二个节点为空 不用排队
	第二个节点的线程不是当前线程排队
	
	
- 非公平锁直接判断state==0,cas抢占


addWaiter
	- 创建node节点
	- 判断当前tail是不是空,不是空
		- 把node节点的头设置为tail 会不会多个节点的前节点都是tail?似乎关系不大
		- 需要把tail节点的尾设置为node cas
    - tail是空,执行enq(node)
    
    
enq(node)
 死循环
 判断tail是不是空,可能判断的是够其他线程已经初始化了
 - 空 初始化并设置头尾节点
 - 不为空 把node节点的头设置为tail 会不会多个节点的前节点都是tail?似乎关系不大
 - 需要把tail节点的尾设置为node cas
 
 
addWaiter肯定成功,返回刚刚入队的node
acquireQueued(node, arg)

循环
  - 判断当前节点的前置节点是头结点,tryAcquire(1)
  	- 获取成功设置头结点为当前节点
  - 不是头结点
  	- 判断需不需要挂起shouldParkAfterFailedAcquire(Node pred, Node node)
  		- 前置节点是waitStatus=Node.SIGNAL=-1 return true
		- pred.waitStatus>0 任务可能被取消,自循环
		node不变找到waitStatus<=0的节点,把node和pred之前满足条件的一个node链接起来 返回false
		- pred.waitStatus<=0设置 pred的waitStatus=Node.SIGNA cas 返回false
	- parkAndCheckInterrupt 线程挂起并且返回线程中断状态 park 并且thread.in
finally
   - 这里不用看了,目前除了lock几十亿




release
	1.boolean release = tryRelease(arg);
		-  1.c=state-1
         * 2.检查是不是当前线程持有锁,不是抛异常
         * 3.检查state==0 是设置当前占用线程为null
         * 4.设置state的值为c
	2.释放成功unpark后继节点
		-这里会把当前节点的waitStatus
		//com.git.concurrent.locks.ReentrantLock.NonfairSync#lock
		final void lock() {
    
    
            if (compareAndSetState(0, 1))
                setExclusiveOwnerThread(Thread.currentThread());
            else
                acquire(1);
        }
        
        //com.git.concurrent.locks.ReentrantLock.FairSync#lock
        final void lock() {
    
    
            acquire(1);
        }
            
//jdk源码考出来把if的多个步骤拆分出来
public final void acquire(int arg) {
    
    
        //获取成功,返回false
        boolean tryFail = tryAcquire(arg);
        if(tryFail) return;
        //入队
        Node node = addWaiter(Node.EXCLUSIVE);
        //获取到了就是false,没有获取到的线程被挂起,第二个节点会一直尝试获取,只有一种情况 线程被中断才会返回true
        boolean acquireQueued = acquireQueued(node, arg);
        //线程中断
        if (acquireQueued) selfInterrupt();
    }

1.tryAcquire

	//tryAcquire(1)
	//com.git.concurrent.locks.ReentrantLock.FairSync#tryAcquire
		protected final boolean tryAcquire(int acquires) {
    
    
            final Thread current = Thread.currentThread();
            int c = getState();
            if (c == 0) {
    
    
                //唯一区别多了一个hasQueuedPredecessors,如果不需要排队在进行设置,保证先来后到的顺序
                if (!hasQueuedPredecessors() && compareAndSetState(0, acquires)) {
    
    
                    setExclusiveOwnerThread(current);
                    return true;
                }
            }
            else if (current == getExclusiveOwnerThread()) {
    
    
                int nextc = c + acquires;
                if (nextc < 0)
                    throw new Error("Maximum lock count exceeded");
                setState(nextc);
                return true;
            }
            return false;
        }
        
    



1.1 hasQueuedPredecessors

//	
	public final boolean hasQueuedPredecessors() {
    
    
        Node t = tail; // Read fields in reverse initialization order
        Node h = head;
        // 1.两个都为null,还没有初始化 null==null true 返回false不用排队
        // 2.head==tail表示 头尾节点相同,不用排队同1
        if(h == t) return false;

        // 3.head为null  tail不为null 直接空指针了,这种情况不会出现
        Node s = h.next;

        // 4.head不为null  tail为null 可能正在初始化 这种情况可能在初始化直接返回true排队
        if(s == null) return true;

        //到了这一步队列里面起码已经有两个节点,后记节点不是当先线程操作,直接排队 返回true
        return s.thread != Thread.currentThread();

    }

2.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) {
    
    
            //当前节点前一个节点是尾节点?会不会多个节点的前节点都是tail?似乎关系不大
            node.prev = pred;
            //把尾节点设置为当前
            if (compareAndSetTail(pred, node)) {
    
    
                //前尾节点,的后继节点改为当前尾节点
                pred.next = node;
                return node;
            }
        }
        //尾节点为空
        enq(node);
        return node;
    }

2.1 enq(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;
                }
            }
        }
    }

3.acquireQueued(node, arg)

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;
                }
                //当前节点不是老二 或者获取失败 获取失败要不要挂起来,第一次返回false继续循环
                if (shouldParkAfterFailedAcquire(p, node) && parkAndCheckInterrupt())
                    interrupted = true;
            }
        } finally {
    
    
            //目前就猜到一种可能性,重入次数过大,int为负值 tryAcquire爆出异常
            if (failed){
    
    
                System.out.println("acquireQueued failed="+failed);
                cancelAcquire(node);
            }

        }
    }

3.1 shouldParkAfterFailedAcquire

private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
    
    
        System.err.println("当前线程"+Thread.currentThread().getName());
        //前置节点的waitStatus
        int ws = pred.waitStatus;
        //如果是SIGNAL
        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) {
    
    
            //ws>0表示cancel,直接移除队列
            do {
    
    
                pred = pred.prev;
                node.prev = pred;
            } while (pred.waitStatus > 0);
            pred.next = node;
        } else {
    
    
            /*
             * waitStatus must be 0 or PROPAGATE.  Indicate that we
             * need a signal, but don't park yet.  Caller will need to
             * retry to make sure it cannot acquire before parking.
             */
            //第一次进来把前置节点设置为-1
            compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
        }
        return false;
    }

3.2 parkAndCheckInterrupt()

private final boolean parkAndCheckInterrupt() {
    
    
        java.util.concurrent.locks.LockSupport.park(this);
        return Thread.interrupted();
    }

4. selfInterrupt

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

5.release

public final boolean release(int arg) {
    
    

        boolean release = tryRelease(arg);

        if(!release) return false;
        //释放成功 unpark后继节点
        Node h = head;
        if (h != null && h.waitStatus != 0)
            unparkSuccessor(h);
        return true;
    }

5.1 tryRelease

/**
         * 1.c=state-1
         * 2.检查是不是当前线程持有锁,不是抛异常
         * 3.检查state==0 是设置当前占用线程为null
         * 4.设置state的值为c
         * @param releases
         * @return
         */
        protected final boolean tryRelease(int releases) {
    
    
            int c = getState() - releases;
            if (Thread.currentThread() != getExclusiveOwnerThread())
                throw new IllegalMonitorStateException();
            boolean free = false;
            if (c == 0) {
    
    
                free = true;
                setExclusiveOwnerThread(null);
            }
            //c==0释放锁,这是其他线程可能try到了,可能是本线程或者是其他线程
            setState(c);
            return free;
        }

5.2 unparkSuccessor

private void unparkSuccessor(Node node) {
    
    
        /*
         * If status is negative (i.e., possibly needing signal) try
         * to clear in anticipation of signalling.  It is OK if this
         * fails or if status is changed by waiting thread.
         */
        int ws = node.waitStatus;
    
        if (ws < 0)
            compareAndSetWaitStatus(node, ws, 0);

        /**
         * Thread to unpark is held in successor, which is normally
         * just the next node.  But if cancelled or apparently null,
         * traverse backwards from tail to find the actual
         * non-cancelled successor.
         */
        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);
    }

Insert image description here

Guess you like

Origin blog.csdn.net/weixin_43328357/article/details/123280446
Recommended