首页 > 其他分享 >ReentrantLock 使用

ReentrantLock 使用

时间:2024-03-13 17:44:23浏览次数:16  
标签:Thread ReentrantLock 获取 线程 tryLock 使用 公平

ReentrantLock 介绍

ReentrantLock 是 Java 中的一个可重入锁,它提供了与 synchronized 关键字类似的功能,但相比 synchronized,ReentrantLock 提供了更多的灵活性和功能。

定义:ReentrantLock 是一个可重入且独占式的锁,它具有与使用 synchronized 监视器锁相同的基本行为和语义,但与 synchronized 关键字相比,它更灵活、更强大,增加了轮询、超时、中断等高级功能。

ReentrantLock,顾名思义,它是支持可重入锁的锁,是一种递归无阻塞的同步机制。除此之外,该锁还支持获取锁时的公平和非公平选择。

公平性:ReentrantLock 的内部类 Sync 继承了 AQS,分为公平锁 FairSync 和非公平锁 NonfairSync。

如果在绝对时间上,先对锁进行获取的请求一定先被满足,那么这个锁是公平的,反之,是不公平的。公平锁的获取,也就是等待时间最长的线程最优先获取锁,也可以说锁获取是顺序的。

ReentrantLock 的公平与否,可以通过它的构造函数来决定。

ReentrantLock 的主要特点包括:

  1. 可重入性:允许线程多次获取同一把锁,而不会造成死锁。
  2. 公平性:可以选择是否公平地获取锁,公平性可以保证等待时间最长的线程优先获取锁。
  3. 中断响应:支持线程在等待锁的过程中响应中断。
  4. 条件变量:可以使用条件变量来实现更复杂的线程通信。
  5. 锁超时:可以设置获取锁的超时时间。

ReentrantLock 的主要方法包括:

  1. lock():获取锁,如果锁已经被其他线程获取,则当前线程会被阻塞,直到获取到锁。
  2. unlock():释放锁。
  3. tryLock():尝试获取锁,如果获取成功返回 true,否则返回 false。
  4. newCondition():创建一个 Condition 对象,用于线程等待和通知。
@Slf4j
public class LockExample2 {

    // 请求总数
    public static int clientTotal = 5000;
    // 同时并发执行的线程数
    public static int threadTotal = 200;

    public static int count = 0;
    private final static Lock lock = new ReentrantLock();
    public static void main(String[] args) throws Exception {
        ExecutorService executorService = Executors.newCachedThreadPool();
        final Semaphore semaphore = new Semaphore(threadTotal);
        final CountDownLatch countDownLatch = new CountDownLatch(clientTotal);
        for (int i = 0; i < clientTotal ; i++) {
            executorService.execute(() -> {
                try {
                    semaphore.acquire();
                    add();
                    semaphore.release();
                } catch (Exception e) {
                    log.error("exception", e);
                }
                countDownLatch.countDown();
            });
        }
        countDownLatch.await();
        executorService.shutdown();
        log.info("count:{}", count);
    }

    private static void add() {
        lock.lock();
        try {
            count++;
        } finally {
            lock.unlock();
        }
    }
}

 

tryLock 方法

我们之前进行过介绍,Lock 接口包含了两种 tryLock 方法,一种无参数,一种带参数。

  • boolean tryLock():仅在调用时锁为空闲状态才获取该锁。如果锁可用,则获取锁,并立即返回值 true。如果锁不可用,则此方法将立即返回值 false;
  • boolean tryLock(long time, TimeUnit unit):如果锁在给定的等待时间内空闲,并且当前线程未被中断,则获取锁;
 try {
            if(locks.tryLock(4000,TimeUnit.MILLISECONDS)){ //尝试获取锁,获取成功则进入执行,不成功则执行finally模块
                System.out.println(Thread.currentThread().getName()+"-->");
                Thread.sleep(5000);
            }else{
                System.out.println(Thread.currentThread().getName()+" time out ");
            }
        } catch (InterruptedException e) {
             e.printStackTrace();
        }finally {
            try {
                locks.unlock();
            } catch (Exception e) {
                System.out.println(Thread.currentThread().getName() + "未获取到锁,释放锁抛出异常");
            }
        }

结果分析:tryLock 方法,虽然等待 4000 毫秒,但是这段时间不足以等待 Thread-1 释放资源锁,所以还是超时。

公平锁与非公平锁

分类:根据线程获取锁的抢占机制,锁可以分为公平锁和非公平锁。

公平锁:表示线程获取锁的顺序是按照线程请求锁的时间早晚来决定的,也就是最早请求锁的线程将最早获取到锁。

非公平锁:非公平锁则在运行时闯入,不遵循先到先执行的规则。

ReentrantLock:ReentrantLock 提供了公平和非公平锁的实现。

ReentrantLock 实例:

//公平锁
ReentrantLock pairLock = new ReentrantLock(true);
//非公平锁
ReentrantLock pairLock1 = new ReentrantLock(false);
//如果构造函数不传递参数,则默认是非公平锁。
ReentrantLock pairLock2 = new ReentrantLock();

场景介绍:通过模拟一个场景假设,来了解公平锁与非公平锁。

  • 假设线程 A 已经持有了锁,这时候线程 B 请求该锁将会被挂起;
  • 当线程 A 释放锁后,假如当前有线程 C 也需要获取该锁,如果采用非公平锁方式,则根据线程调度策略,线程 B 和线程 C 两者之一可能获取锁,这时候不需要任何其他干涉;
  • 而如果使用公平锁则需要把 C 挂起,让 B 获取当前锁,因为 B 先到所以先执行。

Tips:在没有公平性需求的前提下尽量使用非公平锁,因为公平锁会带来性能开销。

 ReentrantLock 其他方法介绍

对 ReentrantLock 来说,方法很多样,如下介绍 ReentrantLock 其他的方法,有兴趣的同学可以自行的尝试使用。

  • getHoldCount():当前线程调用 lock () 方法的次数;
  • getQueueLength():当前正在等待获取 Lock 锁的线程的估计数;
  • getWaitQueueLength(Condition condition):当前正在等待状态的线程的估计数,需要传入 Condition 对象;
  • hasWaiters(Condition condition):查询是否有线程正在等待与 Lock 锁有关的 Condition 条件;
  • hasQueuedThread(Thread thread):查询指定的线程是否正在等待获取 Lock 锁;
  • hasQueuedThreads():查询是否有线程正在等待获取此锁定;
  • isFair():判断当前 Lock 锁是不是公平锁;
  • isHeldByCurrentThread():查询当前线程是否保持此锁定;
  • isLocked():查询此锁定是否由任意线程保持。

 

 

 

标签:Thread,ReentrantLock,获取,线程,tryLock,使用,公平
From: https://www.cnblogs.com/RedOrange/p/18056899

相关文章

  • pytest测试框架基本使用
    一、pytest测试框架简介pytest是Python中的单元测试框架1、pytest特点:。容易上手,入门简单,丰富的文档资料,文档中有很多实例可进行参考。支持参数化。执行用例过程中可以进行标记跳过用例,标记失败用例。支持重复执行失败的用例。具有很多的第三方插件,并且可以实现自定义......
  • 【C++】thread 头文件无法正常使用问题
    问题当我使用MinGWGCC,在windows上编写C++程序的时候,使用thread类会无法编译,有如下错误:我使用的是c++17这个问题原因是MinGWGCC当前仍缺少标准C++11及以上版本线程类的实现。解决方案Stackoverflow上的类似问题:传送门1.下载源文件:源文件外网可能比较慢,提供C......
  • 【Python使用】嘿马头条完整开发md笔记第1篇:课程简介,ToutiaoWeb虚拟机使用说明【附代
    嘿马头条项目从到完整开发笔记总结完整教程(附代码资料)主要内容讲述:课程简介,ToutiaoWeb虚拟机使用说明,Pycharm远程开发,产品与开发,数据库1产品介绍,2原型图与UI图,3技术架构,4开发。OSS对象存储,七牛云存储,CDN,缓存。缓存,缓存架构,缓存数据,缓存有效期与淘汰策略,缓存模式缓存数据的......
  • gitlab-ci 使用钉钉进行Job通知
    首先注册登录钉钉自行查询方法吧1、这里要提一下钉钉注册登录好之后在手机上是无法看到钉钉的webhook信息的,需要使用PC登录查看具体方法如下首先钉钉创建群聊,选择机器人  添加机器人 我这里添加了两个机器人gitlab 和自定义 先了解下gitlab机器人配置方法......
  • Taro微信小程序使用表单组件rc-field-form
    安装rc-field-formyarnaddrc-field-form使用import{View,Button,Input}from"@tarojs/components";importForm,{Field,useForm}from"rc-field-form";exportdefaultfunctionInstallParameter(){const[form]=useForm();co......
  • setvbuf缓冲的使用
    平时我们在写文件的时候,iofstream也好,fwrite也罢,写文件到磁盘,刷新、落盘,这样就完成了一次磁盘IO交互;当出现高并发,多个线程都在写磁盘的时候,就可能出现磁盘IO瓶颈,如图,写等待的时间就会很长,这将一定程度阻塞程序的运行或者影响正常存储:#iostat-x-d/dev/sda-m1针对这种问题......
  • kubernetes中使用Service反向代理外部服务
    参考https://blog.csdn.net/weixin_43334786/article/details/128432325当我们的某个服务在外部集群的时候,但是又想k8s集群内的应用连接它,这是可以创建一个service,用service代理外部服务,然后集群内就能连接该service,从而间接的访问外部服务。创建一个service代理外部的服务创......
  • 不使用telnet进行端口测试的方法
    不使用telnet进行端口测试的方法 测试通过样例[root@ip203~]#curl-v10.0.0.210:8082*Abouttoconnect()to10.0.0.210port8082(#0)*Trying10.0.0.210...*Connectedto10.0.0.210(10.0.0.210)port8082(#0)>GET/HTTP/1.1>User-Agent:curl/7.29......
  • 痞子衡嵌入式:使用恩智浦GUI Guider快速创建全新LCD屏示例工程的步骤
    大家好,我是痞子衡,是正经搞技术的痞子。今天痞子衡给大家分享的是使用恩智浦GUIGuider快速创建全新LCD屏示例工程的步骤。在痞子衡旧文《在i.MXRT1170上快速点亮一款全新LCD屏的方法与步骤》里,痞子衡介绍了在官方SDK裸机驱动elcdif示例工程基础上做修改以支持一款......
  • Maven的基本安装与使用
    前言Maven翻译为"专家"、"内行",是Apache下的一个纯Java开发的开源项目。基于项目对象模型(缩写:POM)概念,Maven利用一个中央信息片断能管理一个项目的构建、报告和文档等步骤。Maven是一个项目管理工具,可以对Java项目进行构建、依赖管理。简单来说,Maven是一个框架,可以简化......