20230608 java.util.concurrent.locks.ReentrantLock

发布时间 2023-08-22 17:42:50作者: 流星<。)#)))≦

介绍

  • java.util.concurrent.locks.ReentrantLock
  • public class ReentrantLock implements Lock, java.io.Serializable
  • ReentrantLock 是使用 AQS 的标准范式

API

构造器

  • ReentrantLock()
  • ReentrantLock(boolean fair)
    • fair :是否公平锁,默认非公平锁

public

实现接口 java.util.concurrent.locks.Lock

  • lock
  • lockInterruptibly
  • tryLock
  • tryLock
  • unlock
  • newCondition

其他 public

  • getHoldCount
    • 当前线程持有此锁的次数,如果此锁未被当前线程持有,则为零
  • isHeldByCurrentThread
    • 查询此锁是否由当前线程持有
  • isLocked
    • 查询此锁是否被任何线程持有
    • 此方法设计用于监视系统状态,而不用于同步控制
  • isFair
    • 是否公平锁
  • hasQueuedThreads
    • final boolean hasQueuedThreads()
    • 查询是否有任何线程正在等待获取此锁
    • 注意,因为取消可能随时发生,所以true返回并不能保证任何其他线程都会获得此锁。此方法主要用于监视系统状态。
  • hasQueuedThread
    • final boolean hasQueuedThread(Thread thread)
    • 查询入参线程是否正在等待获取此锁
  • getQueueLength
    • int getQueueLength()
    • 返回等待获取此锁的线程数的估计值
    • 该值只是一个估计值,因为当此方法遍历内部数据结构时,线程数可能会动态变化。此方法设计用于监视系统状态,而不用于同步控制
  • hasWaiters
    • boolean hasWaiters(Condition condition)
    • 查询是否有任何线程正在等待与此锁关联的 Condition
    • 注意,由于超时和中断可能随时发生,因此true返回并不能保证未来的signal会唤醒任何线程。此方法主要用于监视系统状态。
  • getWaitQueueLength
    • int getWaitQueueLength(Condition condition)
    • 返回等待与此锁关联的 Condition 的线程数的估计值

代码理解

ReentrantLock 实现 Lock 接口,内部锁实现使用 AQS AbstractQueuedSynchronizer

读代码时,需要关联 AbstractQueuedSynchronizer 一起读

包含三个静态内部类,分别是

  • abstract static class Sync extends AbstractQueuedSynchronizer
  • static final class NonfairSync extends Sync
  • static final class FairSync extends Sync

定义同步器:

private final Sync sync;

AbstractQueuedSynchronizer.stateReentrantLock 中代表的是线程持有锁的次数

公平锁

公平锁的实现对比 FairSyncNonfairSync ,区别在于

  • initialTryLock
  • tryAcquire

这两个方法都在 ReentrantLock#lock 方法调用中用到,两者实现的区别是 FairSync 在设置 state 前会调用 hasQueuedPredecessors 判断是否有任何线程等待获取的时间比当前线程长

ReentrantLock#tryLock 始终是非公平的

示例代码

用于调试理解的示例代码:

package study.hwj.v1p12.lock;

import java.util.Arrays;
import java.util.Map;
import java.util.concurrent.locks.ReentrantLock;

/**
 * TestReentrantLock
 *
 * @author owenwjhuang
 * @date 2023/6/8
 */
public class TestReentrantLock {
    public static void main(String[] args) throws InterruptedException {
        // testTryLock();
        // testSingleThread();

        testTwoThread();

        // testThreeThread();

    }

    private static void testThreeThread() {
        ReentrantLock reentrantLock = new ReentrantLock();

        Runnable runnable = () -> {
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
                throw new RuntimeException(e);
            }
            System.out.println(Thread.currentThread() + ":11:" + reentrantLock);
            reentrantLock.lock();
            System.out.println(Thread.currentThread() + ":12:" + reentrantLock);
        };

        Thread thread1 = new Thread(runnable, "111");
        Thread thread2 = new Thread(runnable, "222");

        System.out.println(Thread.currentThread() + ":00:" + reentrantLock);
        reentrantLock.lock();
        System.out.println(Thread.currentThread() + ":01:" + reentrantLock);

        thread1.start();
        thread2.start();

        Map<Thread, StackTraceElement[]> allStackTraces = Thread.getAllStackTraces();
        allStackTraces.forEach((k, v) -> {
            System.out.println("==============");
            System.out.println(k);
            System.out.println(Arrays.toString(v));
        });


    }

    /**
     * 单个线程
     */
    private static void testTwoThread() throws InterruptedException {
        ReentrantLock reentrantLock = new ReentrantLock();

        new Thread(() -> {
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println(Thread.currentThread().getName());
            reentrantLock.lock();

            reentrantLock.unlock();
        }).start();

        Thread.sleep(1000);
        System.out.println(Thread.currentThread().getName());

        reentrantLock.lock();

        Thread.sleep(100000);
        reentrantLock.unlock();

    }


    /**
     * 单个线程
     */
    private static void testSingleThread() {
        ReentrantLock reentrantLock = new ReentrantLock();

        System.out.println("1::" + reentrantLock);
        reentrantLock.lock();
        System.out.println("2::" + reentrantLock);
        reentrantLock.lock();
        System.out.println("3::" + reentrantLock);
        reentrantLock.unlock();
        System.out.println("4::" + reentrantLock);
    }

    private static void testTryLock() {
        ReentrantLock reentrantLock = new ReentrantLock();

        System.out.println("1::" + reentrantLock);
        boolean b1 = reentrantLock.tryLock();
        System.out.println("b1::" + b1);
        System.out.println("2::" + reentrantLock);
        boolean b2 = reentrantLock.tryLock();
        System.out.println("b2::" + b2);
        System.out.println("3::" + reentrantLock);
        reentrantLock.unlock();
        System.out.println("4::" + reentrantLock);
    }
}