Java可重入锁怎么释放资源的

在读ReentrantLock重入锁的源码读的不是很懂

img

1、我发现,当重入锁释放资源的时候是通过判断头节点的的waitStatus是否小于0小于0则释放该锁,但释放锁的时候,会将该头节点的waiteStatus设置为0标识该头节点,为一个无用的节点
2、当执行释放锁的动作时,如果发现当前线程因为某些原因被取消的时候,就会从链表的尾部,往前面找一个watStatus=-1的节点进行锁的释放

3、当将头节点设置为0之后,如果后面又有线程执行锁的释放该怎么办
4、当发现当前需要释放锁的线程被取消了之后,就从尾节点向前找一个节点进行释放,这样真的好吗,万一释放错了呢

TechWhizKid参考GPT回答:

  1. waitStatus在阻塞队列中是一个重要的属性,它表示节点的状态。这个属性有几个关键值:CANCELLED (1) 表示当前的线程被取消;SIGNAL (-1) 表示当前节点的后继节点包含的线程需要运行,也就是说前驱节点释放同步状态后需要通知后继节点;等等。当 waitStatus 小于 0 时,也就是值为 SIGNAL 或者 CONDITION 或者 PROPAGATE,说明当前的线程是在等待同步状态。所以,当头节点的状态小于0,那么释放锁,否则,不释放。

  2. 如果当前线程被取消(waitStatus设为CANCELLED),从队尾向前寻找waitStatus<=0的节点是为了保证锁的公平性,而且队列中的每个节点都记录了其前驱和后继,所以这样设计可以尽可能减少对队列的遍历,从而提高效率。

  3. 如果将头节点的waitStatus设为0,那么此时如果有线程试图释放锁,因为这个节点的waitStatus不小于0,所以不会释放,这样保证了公平性。这个头节点的waitStatus会在后续的操作中被修改。

  4. 如果当前需要释放锁的线程被取消,那么从尾节点向前寻找一个节点进行释放,这种做法并不会释放错。因为每个节点都保存了对应线程的引用,而且链表中的节点顺序是等待获取锁的线程顺序,这就保证了公平性。无论是从头部还是从尾部找到的第一个待释放的节点(waitStatus<=0),都是最应该获取锁的线程。

首先呢 这个unpark 方法解除线程的阻塞状态,从而让目标线程能够继续执行。
可以看一下waitstatus这个状态枚举值的含义

       /** waitStatus value to indicate thread has cancelled */
        static final int CANCELLED =  1;
        /** waitStatus value to indicate successor's thread needs unparking */
        static final int SIGNAL    = -1;
        /** waitStatus value to indicate thread is waiting on condition */
        static final int CONDITION = -2;
        /**
         * waitStatus value to indicate the next acquireShared should
         * unconditionally propagate
         */
        static final int PROPAGATE = -3;

如上可知,waitstatus<0需要被唤醒,也就是等待队列,通过检查和设置节点的 waitstatus 来实现线程的挂起和唤醒。然后你说的第四点是不对的。不是从尾节点向前找一个节点进行释放,从尾结点向前找到一个待唤醒的节点,这样也保证了队列内的先来后到,保证队列内的公平。
以上拙见,还望能得到帮助,如果能的话方便点一个采纳~ 谢谢