(五)JDK锁源码分析之可重入锁ReentrantLock

  • 概述
    什么叫可重入锁,简而言之就是同一个线程可以多次获取锁而不被阻塞

  • 使用举例

public static void main(String[] args) {

        for(int i=0;i<2;i++){
            new Thread(new TestLock()).start();
        }

        System.out.println("创建线程完成");
        //new Thread(new TestLock()).start();
    }

    private static class TestLock implements Runnable{

        private static int a=0;

        private static ReentrantLock reentrantLock = new ReentrantLock();

        @Override
        public void run() {
            reentrantLock.lock();
            a++;
            try {
                Thread.sleep(2000);
                System.out.println(Thread.currentThread().getName()+"-a="+a);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            reentrantLock.unlock();
        }
    }

这段代码,执行的结果 会输出一个 a=1 和 a=2(代码可能不太严谨), 程序起了两个线程,因为使用了锁,所以a的值不会出现覆盖问题,会一个个线程排队去执行.

  • ReentrantLock构造
    在这里插入图片描述
    我们看到这个构造,可能会看到比较奇怪, 里面直接给一个sync的变量赋值, 其实ReentrantLock就是一个代理而已,在调用lock方法,其实使用的真正lock方法是调用sync的,在
    ReentrantLock内部有两种实现如下:
    在这里插入图片描述
    在这里插入图片描述
    我们可以看到,两个内部实现,都实现了lock方法,这个才是真正代理背后去获取锁的实现方法.

-lock方法(非公平方式)
在这里插入图片描述
在lock方法中首先通过原子操作去获取锁, 被锁定的状态下值大于0,没被锁定情况下状态中为1, 如果获取到锁,那么就会把当前线程设置为锁持有的线程, 如果没有获取到锁,那么调用acquire方法进行等待,那么是怎么等待的呢?
在这里插入图片描述
acquire其实是父类(AbstractQueuedSynchronizer 同步器)的一个模版方法,具体怎么去实现,根据锁的特性去实现,acquire方法只是作为一个主流程算法的一个控制,我们看看主流程
1.调用tryAcquire方法去尝试获取锁, 同一个线程可以多次获得锁
在这里插入图片描述
2.首先调用addWaiter方法使用尾插法将任务加入到队列,然后方法acquireQueued使用cas算法去轮训获取锁,阻塞当前线程
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • unlock方法
    unlock方法原理很简单,就是直接去释放锁,也就是把当前状态值进行一个减少,减到0就表示当前线程已经释放锁,这个释放锁是不需要做线程安全的, 因为重入锁是一种独占锁,在没释放前提下,其他线程都是被阻塞的,所以释放锁操作会简单许多,只是状态值进行减小
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    直接将状态值减少,这是重入锁的特性,状态值会大于1,有个线程可以重复获取锁
发布了65 篇原创文章 · 获赞 11 · 访问量 7140

猜你喜欢

转载自blog.csdn.net/weixin_38312719/article/details/102926725