image.png
    1.可重入锁
    实现机制

    1. final void lock() { //CAS的方式获取锁,设置status = 1
    2. if (compareAndSetState(0, 1)) //设置为当前线程占有
    3. setExclusiveOwnerThread(Thread.currentThread());
    4. else //判断是否需要阻塞
    5. acquire(1); //如果当前线程占有status + 1, 否则尝试占有锁
    6. }

    2.多condition锁
    condition队列,转移到线程阻塞队列
    构建多个等待队列

    3.可以设置是否为公/非公平锁
    非公平锁,无需判断自己是否进入队列
    公平锁会判断自己是否是头节点来保证fifo,也就是必须入队列且自己为头节点

    1. /**
    2. 在所有线程被LockSupport挂起之后,那么不论是公平锁,还是非公平锁,都是默认唤醒队列中当前线程的下一个线程
    3. 然而,非公平锁的非公平体现在,tryAcquire()方法上!!!
    4. 我们再回头看一下fairSync和unfairSync的tryAcquire方法
    5. 核心点来了:
    6. ·······························································
    7. 公平锁,若队列不为空,没入队的线程不得抢锁,
    8. 非公平锁,若队列不为空,没入队的线程却可以抢锁,
    9. 这时后到的线程可能先抢到锁,即不公平。
    10. ·······························································
    11. 读者可能还会有点迷惑,那是没入队的不可以抢锁,没入队的可以抢锁
    12. 我们再仔细体会这两个方法。
    13. ·················
    14. 如果是非公平锁,记还没进aqs队列的线程为A,在运行的线程为B,队列中B的next记为B.next。
    15. 那么这个时候A和B.next是可以同时竞争这个锁的。
    16. 如果是非公平锁,记还没进aqs队列的线程为A,在运行的线程为B,队列中的next记为B.next。
    17. 那么这个时候tryAcquire的时候,因为有队列中还有节点,那么这个tryAcquire方法一定是false。
    18. 因此这个A线程一定会进入aqs队列然后不断的for循环tryAcquire,如果队列中就剩它这个A节点了,那么在tryAcuqire中
    19. 才会激活。或者在几次for循环后被LockSupport给挂起,等待他的前驱线程来唤醒它。
    20. ·················
    21. */
    22. //这是公平锁
    23. protected final boolean tryAcquire(int acquires) {
    24. if (getState() == 0 && !hasQueuedPredecessors() &&
    25. compareAndSetState(0, acquires)) {
    26. setExclusiveOwnerThread(Thread.currentThread());
    27. return true;
    28. }
    29. return false;
    30. }
    31. //这是非公平锁
    32. protected final boolean tryAcquire(int acquires) {
    33. if (getState() == 0 && compareAndSetState(0, acquires)) {
    34. setExclusiveOwnerThread(Thread.currentThread());
    35. return true;
    36. }
    37. return false;
    38. }

    因此ReentrantLock 只有头节点线程A和新加入的线程B会产生竞争,也就是非公平。

    4.lock的等待机制使用
    加锁时循环四次尝试拿取锁,否则直接
    LockSupport.park(); 精准到指定线程等待。