ReentrantLock源码解析

一、总述

1.Java java.util.concurrent包下的锁的原理其实都差不多,如下:

AQS原理(共享资源+FIFO先进先出队列)+ LockSupport.park(Thread) 阻塞当前线程+ LockSupport.unpark(Thread) 唤醒队列中的线程

2.Java中锁的阻塞和唤醒底层都是通过LockSupport实现的,LockSupport的底层是Unsafe接口,Unsafe是一个提供硬件级别的原子操作相关的接口,可实现线程的挂起及恢复,还可实现多线程同步(包括锁机制、CAS)等操作。

3.其中ReentrantLock的AQS(AbstractQueuedSynchronizer)共享资源为:int state(当前锁是否被持有),Thread exclusiveOwnerThread(持有锁的线程);FIFO先进先出队列数据结构为Node(双向链表)

二、ReetrantLock、ReetrantLock的Condition源码解析

1.我们按照下边代码执行顺序进行源码解析(此处解析的是ReetrantLock默认的非公平锁)

非公平锁就是 thread1获取到锁,thread2在队列中排队等待获取锁,thread1释放锁时,这时候thread3也正好想要获取锁,这时候thread2和thread3都有可能获取到锁,即虽然thread2在队列中等了一段时间,但是未入队列的thread3也是可以抢到锁的;

公平锁就是thread1获取到锁,thread2在队列中排队等待获取锁,thread1释放锁时,这时候thread3也正好想要获取锁,却发现队列中已经有线程在等待了,这时候thread3就直接加入队列,所以排在队列前边的thread2获取到锁了。

private final static  ReentrantLock lock = new ReentrantLock();
private final static Condition condition = lock.newCondition();

@org.junit.Test
public void testArrayBlockingQueue(){
    Thread thread1 = new Thread(() -> {
        lock.lock();
        try {
            System.out.println("thread1 await start.");
            condition.await();
            System.out.println("thread1 await end.");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            System.out.println("thread1 unlock start.");
            lock.unlock();
            System.out.println("thread1 unlock end.");
        }
    });
    thread1.setName("thread1");
    thread1.start();
    
    //确保thread1先执行
    try {
        Thread.sleep(1000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }    

    Thread thread2 = new Thread(() -> {
        lock.lock();
        try {
            System.out.println("thread2 sleep start.");
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("thread2 notify start.");
            condition.signal();
            System.out.println("thread2 notify end.");
        }finally {
            System.out.println("thread2 unlock start.");
            lock.unlock();
            System.out.println("thread2 unlock end.");
        }
    });
    thread2.setName("thread2");
    thread2.start();
    
    //确保thread2先执行
    try {
        Thread.sleep(1000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    
    Thread thread3 = new Thread(() -> {
        lock.lock();
        try {
            System.out.println("thread3 do some thing.");
        }finally {
            System.out.println("thread3 unlock start.");
            lock.unlock();
            System.out.println("thread3 unlock end.");
        }
    });
    thread3.setName("thread3");
    thread3.start();

    try {
        Thread.sleep(3000000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

2.实例化

2.thread1 lock.lock()

thread1获取到锁

2.thread2 lock.lock()

thread2想获取锁,但是由于锁已被thread1获取,所以thread2被挂起并放入线程等待队列,等待锁释放后被唤醒重新获取锁。

3.thread3 lock.lock()

thread3想获取锁,但是由于锁已被thread获取,所以thread3被挂起并放入线程等待队列,等待释放后被唤醒重新获取锁

4.thread1 condition.await()

4.1 thread1 执行condition.await(),

4.1.1 线程进入Condition队列等待被唤醒,

4.1.2 释放锁,

4.1.3 唤醒线程等待队列中的头结点线程即thread2,

4.2 thread2被唤醒后再次尝试获取锁,thread2获取锁成功,

4.3 thread2执行下一步代码condition.signal();

5. thread2 condition.signal()

thread2 执行condition.signal(),将Condition队列中的头结点线程即thread1放入线程等待队列,并唤醒thread1,thread1再次尝试获取锁,但因为thread1此时不是线程等待队列的头结点线程,所以再次阻塞。

6. thread2 lock.unlock(),

thread2执行业务逻辑代码完毕后,thread2执行lock.unlock(),释放锁,并唤醒线程等待队列的头结点即thread3,thread3唤醒后尝试获取锁并获取锁成功,然后执行thread3的业务逻辑代码。

7. thread3 lock.unlock()

thread3执行业务逻辑代码完毕后,thread3执行lock.unlock(),释放锁,并唤醒线程等待队列的头结点即thread1,thread1唤醒后尝试获取锁并获取锁成功,然后执行thread1的业务逻辑代码。

8.thread1 lock.unlock()

thread1执行业务逻辑代码完毕后,thread1执行lock.unlock(),释放锁,此时线程等待队列中无线程节点排队等待获取锁了,全部结束。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值