• 简话ReentrantLock的可重入锁概念


        ReentrantLock与synchronized两种锁都具有可重入的特征,实际上是个很简单的概念,但是很多人都是不看源码硬解释,导致问题变得玄乎。今天我就简单的进行一下解释,可重入实际上也就是当前获取到锁执行权限的线程,可以多次调用加锁的过程,而不会影响线程的正常运行。

    一、举个例子

        家里只有一辆车,老大、老二需要使用的时候都要去老爸那儿拿钥匙。

     周一 ,老大:“老爸,给我钥匙我要出去浪”,老爸给了他,后来老二又来要钥匙,老爸说你哥拿走了,明天轮到你。同时记录下“老大获得了汽车”(+1),晚上老大回家报道,老爸消掉记录(-1),汽车空置;

     周二 ,老二:“老爸,给我钥匙我要出去浪”,老爸给了他,后来老大又来要钥匙,老爸说你弟拿走了,明天再来。同时记录下“老二获得了汽车”(+1),晚上老二回家报道,老爸消掉记录(-1),汽车空置;

     他俩只能一人出门一人在家吗?不是的。周三的时候老大老二手拉手一起出去看电影,老大找到老爸,老爸说“可以”,记录下“老大获得了汽车”(+1)。老二跟着找老爸,老爸也说“可以”,同时也做了个记录“老二也在车里”(+1)。晚上老大回家报道,老爸消掉一条记录(-1)。老二跟着报了道,老爸再消一条记录(-1)。汽车空置。但是如果老二先跑去上厕所忘了跟老爸报备,结果汽车仍然被标记占用,那么大家就都用不了了。

      这个例子中,汽车就是我们的锁,老大、老二单独行动就是两个独立的线程,一起行动的话就是一个线程。老爸的记录就是ReentrantLock对象里的 State变量,这个变量是volatile线程共享的。当state=0时,即为资源空置,锁被线程获取后 state将从0 -> 1。当线程中嵌套的内部方法又去请求锁的时候,ReentrantLock会去判断当前线程是否已经获取了锁,如果是,则允许内部方法继续运行,不过此时 state状态要加 1,即从 1 -> 2。ReentrantLock的这个机制就是可重入,如果子方法中还有子方法那么这个值将会从2 -> 3甚至无限大。一个线程重复获取锁的时候,需要成对的去释放锁,将state从n一直减为0,释放资源。少一次释放,资源就被锁死;反过来,那么不可重入就是说当线程已经获得了锁,那么子方法是不允许再写获取锁的逻辑了,否则当前线程也被挂起。

    二、写个测试代码

    /**
     * ReentrantLock 测试
     */
    public class ReentrantLockTest2 {
        public ReentrantLock lock = new ReentrantLock();
        /**
         * 外层方法加锁
         * @throws InterruptedException
         */
        public void test() throws InterruptedException {
            lock.lock();
            try {
                test2();
                // System.out.print("当前锁获得线程:" + Thread.currentThread().getName() + "
    ");
            } catch (Exception e) {
    
            } finally {
                lock.unlock();
            }
        }
        /**
         * 内层方法加锁
         * @throws InterruptedException
         */
        public void test2() throws InterruptedException {
            lock.lock();
            try {
                test();
                System.out.print("当前锁获得线程:" + Thread.currentThread().getName() + "
    ");
            } catch (Exception e) {
    
            } finally {
                lock.unlock();
            }
        }
    
        public static void main(String[] args) throws Exception {
            ReentrantLockTest2 testObj = new ReentrantLockTest2();
            ExecutorService executorService = Executors.newCachedThreadPool();
            for (int i = 0; i < 2; i++) {
                int finalI = i;
                executorService.submit(() -> {
                    try {
                        Thread.currentThread().setName("任务"+ finalI);
                        testObj.test();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                });
            }
        }
    }

    三、看看源码

     

     写在最后

      可重入锁实际上就这么简单,state每重入一次就加1,每释放一次就减1。原理很简单,我个人觉得这么做只是为了减少锁机制的使用难度,使用者只用关注方法是否完成了获取锁与释放锁的逻辑。而不用去管调用链上是否已经有人占据了锁。

  • 相关阅读:
    2008年秋季毕业设计总体安排
    2008秋季计算机软件基础0903课堂用例(1)
    收藏:微软新技术不断,开发者如何面对?
    2008秋季计算机软件基础0901课堂用例
    2008秋季计算机软件基础0908课堂用例(1)
    WebBrows仿造Cookie
    ScriptCase价格调整通知
    JavaMail API简介
    Spring攻略学习笔记(3.05)重用切入点定义
    verletjs:超酷的开源JavaScript物理引擎
  • 原文地址:https://www.cnblogs.com/MrSi/p/13982923.html
Copyright © 2020-2023  润新知