多线程应用场景

news2024/10/5 14:24:23

文章目录

  • 前言
  • 一、CountDownLatch倒计时锁
  • 二、如何控制线程并发数?
  • 三、浅聊ThreadLocal
    • 1.ThreadLocal定义
    • 2.ThreadLocal源码解读
    • 3.关于ThreadLocal的一个案例
  • 总结


前言

本篇介绍多线程中的应用场景,比如倒计时锁CountDownLatch、信号量Semaphore、以及ThreadLocal的理解。


一、CountDownLatch倒计时锁

CountDownLatch是JUC包下的一个类,它提供了两个方法一个是countDown(),和await(),通过配合使用可以实现让其他线程执行完再执行当前线程,我们需要创建一个CountDownLatch对象,传入一个计量参数,每次执行countDown方法,计数就会减一,await()会阻塞当前线程继续往下执行,当计数变为0时,当前线程才会继续执行。
代码案例:

public class CountDownLatchDemo {
    public static void main(String[] args) throws InterruptedException {
        // 初始化一个倒计时锁,参数为3
        CountDownLatch latch = new CountDownLatch(3);
        new Thread(()->{
            System.out.println(Thread.currentThread().getName() + "-begin...");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            // count--
            latch.countDown();
            System.out.println(Thread.currentThread().getName()+"-end..." + latch.getCount());
        }, "t1").start();

        new Thread(()->{
            System.out.println(Thread.currentThread().getName() + "-begin...");
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            // count--
            latch.countDown();
            System.out.println(Thread.currentThread().getName()+"-end.." + latch.getCount());
        }, "t2").start();

        new Thread(()->{
            System.out.println(Thread.currentThread().getName() + "-begin...");
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            // count--
            latch.countDown();
            System.out.println(Thread.currentThread().getName()+"-end..." + latch.getCount());
        }, "t3").start();

        String name = Thread.currentThread().getName();
        System.out.println(name + "-waiting...");
        //等待其它线程执行完
        latch.await();
        System.out.println(name + "-wait end...");

    }
}

以上代码中创建了CountDownLatch对象,定义了计量参数为3,同时创建了三个线程,中间分别沉睡了1000ms、3000ms、1500ms,每个线程执行完都会进行countDown操作,等三个线程都执行完计量参数就变成0了,此时主线程的代码才会继续执行。
程序运行结果:
在这里插入图片描述

二、如何控制线程并发数?

多线程中,如何控制接口的并发访问的数量呢,JUC包下提供了一个类,Semaphore信号量,我们需要创建一个Semaphore对象,传入一个允许并发访问的数量,同时线程运行时可以使用acquare()方法让计数减一,当计数减到0,其他线程就会进入等待,直到运行的线程调用release(),计数就会+1,其他线程才可以继续执行。
代码如下:

public class SemaphoreCase {
//    static ThreadLocal<String> threadLocal = new ThreadLocal<>();

    public static void main(String[] args) {

        // 1.创建信号量semaphoreCase对象
        Semaphore semaphore = new Semaphore(3);
        // 2.10个线程同时运行
        for (int i = 0; i < 10; i++){
            new Thread(()->{
                // 获取许可,计数减一
                try {
                    semaphore.acquire();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                try{
                    System.out.println("running...");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                    System.out.println("ending...");
                }
                finally {
                    // 释放许可 计数+1
                    semaphore.release();
                }
            }).start();
        }
    }
}

在这里插入图片描述

三、浅聊ThreadLocal

ThreadLocal是多线程中对于解决线程安全的一个操作类,它会为每个线程都分配一个独立的线程副本从而解决了变量并发访问冲突的问题。而ThreadLocal同时实现了线程内的资源共享。ThreadLocal本质来说就是一个线程内部存储类,从而让多个线程只操作自己内部的值,从而实现线程数据隔离。

1.ThreadLocal定义

  • ThreadLocal可以实现资源对象的线程隔离,让每个线程各用各的资源对象,避免争用引发的线程安全问题
  • ThreadLocal同时实现了线程内的资源共享

2.ThreadLocal源码解读

set方法:
在这里插入图片描述
首先获取当前访问的线程,通过当前线程获取ThreadLocalMap对象,它是ThreadLocal的一个静态内部类,它里面有一个Entry[]数组,用于存储元素信息,如果首次创建就会走else创建map就会走ThreadLocalMap的构造方法逻辑,先取ThreadLocal作为key取它的hash值,然后使用&运算符对数据长度取模得到数组下标,将元素值存储到数组中。
若不是首次创建就会走map.set方法
在这里插入图片描述
如果上次存储了元素,由于两次的ThreadLocal的hash值是一样的,所以本次存储的时候,会进行值替换操作然后return;

get方法:
在这里插入图片描述
get方法就比较简单,也是通过ThreadLocal对象获取它的hash值对数组取模定位下标,然后返回这个下标位置上的值。若没有set操作过,则返回setIntialValue()这个是一个null值。

remove方法:
在这里插入图片描述
remove方法也是同理,找出下标删除数组中的元素即可。

3.关于ThreadLocal的一个案例

public class ThreadLocalCase {
    static ThreadLocal<String> threadLocal = new ThreadLocal<>();

    public static void main(String[] args) throws InterruptedException {
        // 在主线程存储一个字符串数据
        threadLocal.set("test01");
        // 开启一个线程
        new Thread(()->{
            try{
                threadLocal.set("test02");
                // 在子线程中能否获取到存储的test01呢?
                System.out.println(Thread.currentThread().getName() + "-get: " + threadLocal.get());
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }finally {
                // 调用remove方法清楚,避免OOM
                threadLocal.remove();
            }
        }, "t1").start();
        // 主线程中获取存储的test01?
        System.out.println(Thread.currentThread().getName() + "-get: " + threadLocal.get());

        Thread.sleep(1000);
        // 调用remove方法清楚,避免OOM
        threadLocal.remove();
    }

}

以上代码中,在主线程中set一个字符串,同时定义了一个子线程,在子线程中也set一个字符串,两个值是不影响的,主线程只能获取它自己set的值,而子线程也是获取它set的值,运行情况:
在这里插入图片描述


总结

以上是对多线程的一些运用场景进行了分析,以及从源码解读了ThreadLocal为啥能实现资源对象的线程隔离,它为每个线程都分配了一个独立的线程副本,不管是get还是set操作,都会先获取当前访问的线程,从而实现线程隔离。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/763404.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【雕爷学编程】Arduino动手做(163)---大尺寸8x8LED方格屏模块5

37款传感器与模块的提法&#xff0c;在网络上广泛流传&#xff0c;其实Arduino能够兼容的传感器模块肯定是不止37种的。鉴于本人手头积累了一些传感器和执行器模块&#xff0c;依照实践出真知&#xff08;一定要动手做&#xff09;的理念&#xff0c;以学习和交流为目的&#x…

一种简化的3D点云车道线自动识别标注一些思考

0. 简介 作为3D车道线训练来说&#xff0c;数据集是至关重要的&#xff0c;而使用点云的精确性来完成准确的车道线地图构建是一个非常重要且有趣的事情。下面我们将会从一个例子开始&#xff0c;分阶段来告诉大家该怎么样去完成一个简单的3D点云车道线自动识别标注工具。 1. …

WordPress作为可扩展的企业级解决方案

网络商业世界就像一片汪洋大海&#xff0c;大型企业是大海中最大的鱼。然而&#xff0c;只因为你比其他人都大&#xff0c;并不意味着你不能逆流而上。相反&#xff0c;企业业务面临的挑战更大&#xff0c;对网站的技术要求更高。 多年来&#xff0c;大型公司通常依赖最昂贵的…

爆肝整理,接口自动化测试面试题+答案,25k*15薪如何达成的...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 1、请问你是如何做…

MB10S-ASEMI迷你贴片整流桥50MIL芯片MB10S

编辑&#xff1a;ll MB10S-ASEMI迷你贴片整流桥50MIL芯片MB10S 型号&#xff1a;MB10S 品牌&#xff1a;ASEMI 芯片个数&#xff1a;4 封装&#xff1a;MBS-4 恢复时间&#xff1a;50ns 工作温度&#xff1a;-50C~150C 浪涌电流&#xff1a;30A 正向电流&#xff1a;1…

HttpRunner自动化测试之辅助函数debugtalk.py

辅助函数debugtalk.py Httprunner框架中&#xff0c;使用yaml或json文件进行用例描述&#xff0c;无法做一些复杂操作&#xff0c;如保存一些数据跨文件调用&#xff0c;或者实现一些复杂逻辑判断等&#xff0c;为了解决这个问题&#xff0c;引入了debugtalk.py辅助函数来进行一…

Linux操作系统升级低版本的OpenSSH到9.3的高版本

OpenSSH 9.3之前的版本存在各种各样的安全漏洞&#xff0c;为此&#xff0c;我们需要将OpenSSH升级到最新的9.3的版本。 执行&#xff1a;ssh -V&#xff0c;我们可以查看当前的openssh版本 为了避免升级过程中出现意外而导致服务器无法正常使用&#xff0c;建议操作前先对服务…

插槽的使用!!

什么是插槽 插槽&#xff08;Slot&#xff09;是 vue 为组件的封装者提供的能力。允许开发者在封装组件时&#xff0c;把不确定的、希望由用户指定的部分定义为插槽。可以把插槽认为是组件封装期间&#xff0c;为用户预留的内容的占位符 即&#xff1a;使用者来决定某一块区域…

开利网络拜访番禺前后仓国际珠宝基地,以数字化技术赋能产业升级

近日&#xff0c;开利网络拜访位于番禺的前后仓国际珠宝基地&#xff0c;对基地目前的数字化需求和产业升级方向进行了解和探讨。目前&#xff0c;基地拥有以数字贸易综合服务中心&#xff0c;以人才、流量、运营、金融为抓手&#xff0c;以供应链选品、直播电商、跨境电商为媒…

【C++医学影像PACS】CT检查中的三维重建是什么检查?

一、【PACS影像科普】CT检查中的三维重建是什么检查&#xff1f; 三维重建是多层螺旋CT的一个最大的优点&#xff0c;也是影像工作多年来&#xff0c;从横断解剖到多平面&#xff0c;乃至立体的一次飞跃&#xff0c;让抽象变的形象&#xff0c;大大地提高了准确性&#xff0c;为…

大数据测试之数据仓测试怎么做(下)

前面的文章我们为大家介绍了一个常见的互联网大厂的数据仓的技术框架&#xff0c;也就是下面这张图所展示的内容。 为大家介绍了从操作数据层&#xff0c;到DW层&#xff0c;再到汇总数据层&#xff0c;最后到维度层和数据应用层的整个流程。本文我们将整个架构打平来展示制作…

我们正在开发一套组件库,欢迎你的加入~

项目地址 github地址 可以先点进来康康~ 技术栈 目前我们整体采用的是vue3typescriptless作为整体的开发的选择 需要说的是&#xff0c;我们并没有采用很多组件库采用的TSX的写法&#xff0c;而是选择了SFC的写法&#xff0c;这是因为我们觉得对于大部分的vue开发者来说&am…

用得最多的企业文件加密软件【企业文件加密软件前十】

企业文件加密软件是一种专门设计用于保护企业敏感信息的软件工具。它通过使用加密算法将企业的文件、文件夹和移动设备上的数据转化为不可读的格式&#xff0c;以防止未经授权的访问和数据泄露。这些软件通常提供了多种加密算法和安全控制选项&#xff0c;以满足不同企业的安全…

国外访问学者博士后常用的网络视频面试软件

面试是获得邀请函的重要环节&#xff0c;随着网络的广泛应用&#xff0c;现在视频面试逐渐取代了电话面试&#xff0c;本篇知识人网小编介绍几种国外访问学者博士后常用的网络视频软件。 在申请国外博士后或者访问学者职位时&#xff0c;当接收方导师收到CV&#xff08;简历&am…

postgis上传 上千个资源文件

需求背景所需工具解决流程1. 获取文件名信息2.复制到 excel 表格中3.转成 csv 文件 需求背景 需要把上千个文件资源上传到远端&#xff0c;并建立数据表 所需工具 Notepad 7wps office 11.1.0 解决流程 1. 获取文件名信息 复制文件路径&#xff0c;在 cmd 中进到文件夹&…

Python程序设计基础:列表与元组(二)

文章目录 一、数值列表的生成1、通过input()函数输入创建列表2、通过list()函数转换3、列表生成式4、数值列表的几种统计计算 二、元组1、元组的定义2、元组的操作3、元组作为列表元素 三、转换函数1、元组和列表之间的转换2、字符串和列表之间的转换3、split()方法 一、数值列…

深度学习模型:Pytorch搭建ResNet、DenseNet网络,完成一维数据分类任务

2023.7.17 DenseNet和ResNet都是深度学习中常用的网络结构&#xff0c;它们各有优缺点。 DenseNet的优点是可以充分利用网络中的信息&#xff0c;因为每个层都可以接收来自前面所有层的信息。这种密集连接的结构可以提高网络的准确性&#xff0c;减少过拟合的风险。此外&…

教你一招,动态规划思想

动态规划 什么是动态规划&#xff1f; 动态规划也是算法设计的一种方法/思想。它将一个问题分解为相互重叠的子问题&#xff0c;通过反复求解子问题&#xff0c;来解决原来的问题。 基础案例 场景一 斐波那契数列 当前数等于前面两个数的和。 定义子问题&#xff1a;f(n)…

Python异步网络编程框架Twisted使用方法

Twisted概念 Twisted是一个Python异步网络编程框架&#xff0c;它可以帮助我们开发高性能的网络应用程序。它提供了一些基本概念&#xff0c;如reactor、protocol、transport和factory等&#xff0c;用于构建高效的网络应用程序。 优点&#xff1a; 异步并发处理&#xff1a…

Ceph集群

目录 一、存储概述 1.单机存储设备 1.1 DAS 1.2 NAS 1.3 SAN 2. 单机存储的问题 3. 商业存储解决方案 4.分布式存储&#xff08;软件定义的存储 SDS&#xff09; 4.1 分布式存储的类型 二、Ceph简介 1.Ceph 优势 2. Ceph 架构 2.1 RADOS 基础存储系统 2.2 LIBRADOS…