端午内卷之ReentrantLock重入锁的代码分析与演示

117 阅读4分钟
  • 持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第9天,点击查看活动详情

可重入锁(递归锁)

  • 解释一下什么是可重入:一个线程可以重复获取那把锁🔒。也就是第那种递归 调用,可以重复的执行当前方法。

那个类是那种可重入锁:

  • ReentrantLock 这个类就是可重入的
  • 还有那个关键字:synchronized 他也是可重入的 可重入有什么好处:提高代码的封装性
举个两个例子来看看
  • 你在电影院 抢票 。我们在抢票时,两个人不能买同一个座位的票,点击下单的同时,他会锁住当前座位3分钟,在三分钟之类支付就行。对不对。这个时候我们就可以采用 ReentrantLock 来解决这个抢票。这里人就表示 线程。
  • 第二个例子就是给大家展示一下一个线程不断的重入过程

第一个例子代码展示:

首先说一下这个例子我们可以用synchronized来实现。在这里我们采用ReentrantLock 来解决; 上代码:

/*******************************************************************************
 * Package: com.song.boot.springstudy.thread.lock
 * Type:    ReentrantLockCinema
 * Date:    2022-06-04 21:47
 *
 * Copyright (c) 2022 HUANENG GUICHENG TRUST CORP.,LTD All Rights Reserved.
 *
 * You may not use this file except in compliance with the License.
 *******************************************************************************/
package com.song.boot.springstudy.thread.lock;

import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.locks.ReentrantLock;

/**
 * 功能描述:电影院 ReentrantLockCinema
 * 可以提高代码的封装性
 * @author Songxianyang
 * @date 2022-06-04 21:47
 */
@Slf4j
public class ReentrantLockCinema {
    private static ReentrantLock lock = new ReentrantLock();
    
    public static void main(String[] args) {
        
        new Thread(() -> new ReentrantLockCinema().cinema(1)).start();
        new Thread(() -> new ReentrantLockCinema().cinema(2)).start();
        new Thread(() -> new ReentrantLockCinema().cinema(3)).start();
        new Thread(() -> new ReentrantLockCinema().cinema(4)).start();
        
    }
    
    /**
     * 代码的封装业务
     */
    private void cinema(int i) {
        lock.lock();
        try {
            // 具体的业务
            System.out.println("具体的业务在try里面写-执行了哈哈哈" + i + "线程编号  " + Thread.currentThread().getName());
            Thread.sleep(1000);
            System.out.println("成功预定座位号:" + i +"祝您观看愉快!!");
            System.out.println("-------------");
        } catch (InterruptedException e) {
            e.printStackTrace();
            log.info("cinema: "+e);
        } finally {
            lock.unlock();
        }
    }
}

打印的结果为: 在这里插入图片描述

刚刚在写程序的发现了一个比较有意思的问题。分享一下给大家

不加:static

private  ReentrantLock lock = new ReentrantLock();
/*******************************************************************************
 * Package: com.song.boot.springstudy.thread.lock
 * Type:    ReentrantLockCinema
 * Date:    2022-06-04 21:47
 *
 * Copyright (c) 2022 HUANENG GUICHENG TRUST CORP.,LTD All Rights Reserved.
 *
 * You may not use this file except in compliance with the License.
 *******************************************************************************/
package com.song.boot.springstudy.thread.lock;

import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.locks.ReentrantLock;

/**
 * 功能描述:电影院 ReentrantLockCinema
 * 可以提高代码的封装性
 * @author Songxianyang
 * @date 2022-06-04 21:47
 */
@Slf4j
public class ReentrantLockCinema {

    private  ReentrantLock lock = new ReentrantLock();
    
    public static void main(String[] args) {
        
        new Thread(() -> new ReentrantLockCinema().cinema(1)).start();
        new Thread(() -> new ReentrantLockCinema().cinema(2)).start();
        new Thread(() -> new ReentrantLockCinema().cinema(3)).start();
        new Thread(() -> new ReentrantLockCinema().cinema(4)).start();
        
    }
    
    /**
     * 代码的封装业务
     */
    private void cinema(int i) {
        lock.lock();
        try {
            // 具体的业务
            System.out.println("具体的业务在try里面写-执行了哈哈哈" + i + "线程编号  " + Thread.currentThread().getName());
            Thread.sleep(1000);
            System.out.println("成功预定座位号:" + i +"祝您观看愉快!!");
            System.out.println("-------------");
        } catch (InterruptedException e) {
            e.printStackTrace();
            log.info("cinema: "+e);
        } finally {
            lock.unlock();
        }
    }
}

在这里插入图片描述

  • 有点意思 哈哈哈 是不是 分析: static修饰变量,而且是对象的属性。你在操作多个对象的时候他是共享当前变量的副本。 不加关键字static,的时候。每一次线程进来都有一个新的副本。 所以当我在执行,main方法的时候 四个线程进来,不同的ReentrantLock副本。也就是说四个线程同时获得不同的锁。 在这里插入图片描述 我们获取锁的概念是:多个线程去竞争同一把锁。 从而解锁就就从第四个线程 递减这解锁。 这篇文章可以借鉴一下看看

记录一下刚刚写代码 所发生的问题(开心)

重入锁例子2

首先说一下这个方法

  • getHoldCount:查询当前线程持有该锁的次数

代码

/*******************************************************************************
 * Package: com.song.boot.springstudy.thread.lock
 * Type:    ReentrantLockTest
 * Date:    2022-06-04 22:29
 *
 * Copyright (c) 2022 HUANENG GUICHENG TRUST CORP.,LTD All Rights Reserved.
 *
 * You may not use this file except in compliance with the License.
 *******************************************************************************/
package com.song.boot.springstudy.thread.lock;

import java.util.concurrent.locks.ReentrantLock;

/**
 * 功能描述: 一个线程不断的去重入的过程  也是递归的过程
 *
 * @author Songxianyang
 * @date 2022-06-04 22:29
 */
public class ReentrantLockTest {
    private static ReentrantLock lock = new ReentrantLock();
    
    public static void main(String[] args) {
        System.out.println(lock.getHoldCount());
        lock.lock();
        System.out.println(lock.getHoldCount());
        lock.lock();
        System.out.println(lock.getHoldCount());
        lock.lock();
        System.out.println(lock.getHoldCount());
        System.out.println("-----------");
        lock.unlock();
        System.out.println(lock.getHoldCount());
        lock.unlock();
        System.out.println(lock.getHoldCount());
        lock.unlock();
        System.out.println(lock.getHoldCount());
    }
}

效果图

在这里插入图片描述 主线程不断的递归 不断的重入

0  没有获取锁所以打印0
1  获取第一把锁所以打1
2  获取第2把锁所以打印0
3
-----------
2  解锁其中一个后  打印2
1
0  解锁完了打印0