简话ReentrantLock的可重入锁概念

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

1、举个例子spa

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

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

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

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

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

2、写个测试代码资源

/**
 * 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() + "\r\n");
        } catch (Exception e) {

        } finally {
            lock.unlock();
        }
    }
    /**
     * 内层方法加锁
     * @throws InterruptedException
     */
    public void test2() throws InterruptedException {
        lock.lock();
        try {
            test();
            System.out.print("当前锁得到线程:" + Thread.currentThread().getName() + "\r\n");
        } 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();
                }
            });
        }
    }
}

3、看看源码get

 

 写在最后源码

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

相关文章
相关标签/搜索