java 线程安全和多线程

news2024/11/18 22:27:21

文章目录

  • 前言
  • 一、ThreadLocal是什么?
  • 二、synchronized 和 ReentrantLock 都是 Java 中提供的可重入锁,二者的主要区别有以下 5 个:
  • 三、线程安全的集合类有哪些?
  • 四、说一下你对CompletableFuture的理解
  • 四、项目中是如何创建线程池的,为什么不用Executors 去创建线程池
  • 六、ThreadPoolExecutor 参数说明
  • 总结


前言

提示:这里可以添加本文要记录的大概内容:

例如:随着人工智能的不断发展,机器学习这门技术也越来越重要,很多人都开启了学习机器学习,本文就介绍了机器学习的基础内容。


提示:以下是本篇文章正文内容,下面案例可供参考

一、ThreadLocal是什么?

ThreadLocal是用来维护线程中的变量不被其他线程干扰而出现的一个结构,
内部包含一个ThreadLocalMap类,该类为Thread类的一个局部变量,该Map存储的key为ThreadLocal对象自身,value为我们要存储的对象
这样一来,在不同线程中,持有的其实都是当前线程的变量副本,与其他线程完全隔离,以此来保证线程执行过程中不受其他线程的影响。
ThreadLocal又叫做线程局部变量,全称thread local variable,它的使用场合主要是为了解决多线程中因为数据并发产生不一致的问题。
ThreadLocal为每一个线程都提供了变量的副本,使得每一个线程在某一时间访问到的并不是同一个对象,这样就隔离了多个线程对数据的数据共享,这样的结果无非是耗费了内存,也大大减少了线程同步所带来的性能消耗,也减少了线程并发控制的复杂度。

既然这个Entry的key为一个弱引用的threadLocal,那会有什么问题?

关于这个弱应用,当发生gc的时候会将这个弱引用回收掉
当jvm发生gc时,我们的key变为null,相当与下回这个坑位一直被占用,而里面的value为强引用,导致value内存一直占用,产生内存泄漏的问题

为什么ThreadLocal 会发生内存泄漏?
因为ThreadLocal中的key是弱引用,而value是强引用。当ThreadLocal没有被强引用时,在进行垃圾回收时,key会被清理掉,而value 不会被清理掉,这时如果不做任何处理,value将永远不会被回收,产生内存泄漏。

如何解决ThreadLocal的内存泄漏?
其实在ThreadLocal在设计的时候已经考虑到了这种情况,在调用set()、get() 、remove()等方法时就会清理掉key为null 的记录,所以在使用完ThreadLocal 后最好手动调用remove()方法。

为什么要将key设计成ThreadLocal的弱引用?
如果ThreadLocal的 key是强引用,是会发生内存泄漏的。如果ThreadLocal的key是强引用,引用的ThreadLocal 的对象被回收了,但是 ThreadLocalMap还持有ThreadLocal 的强引用,如果没有手动删除,ThreadLocal 不会被回收,发生内存泄漏。
如果是弱引用的话,引用的ThreadLocal的对象被回收了,即使没有手动删除,ThreadLocal也会被回收。value也会在ThreadLocalMap调用set() 、get()、remove()的时候会被清除。
所以两种方案比较下来,还是ThreadLoacl 的key为弱引用好一些。

ThreadLocal 内存泄露问题是怎么导致的?

ThreadLocalMap 中使用的 key 为 ThreadLocal 的弱引用,而 value 是强引用。所以,如果 ThreadLocal 没有被外部强引用的情况下,在垃圾回收的时候,key 会被清理掉,而 value 不会被清理掉。
这样一来,ThreadLocalMap 中就会出现 key 为 null 的 Entry。假如我们不做任何措施的话,value 永远无法被 GC 回收,这个时候就可能会产生内存泄露。
ThreadLocalMap 实现中已经考虑了这种情况,在调用 set()、get()、remove() 方法的时候,会清理掉 key 为 null 的记录。使用完 ThreadLocal方法后 最好手动调用remove()方法

ThreadLocal 常见应用场景:
使用场景一:代替参数的显式传递 (注意:这个场景其实使用的比较少,一方面显式传参比较容易理解,另一方面我们可以将多个参数封装为对象去传递。)

使用场景二:全局存储用户信息(项目中用到)
使用场景三:解决线程安全问题
数据库连接,连接后存入ThreadLocal中,如此一来,每一个请求线程都保存有一份自己的Connection。于是便解决了线程安全问题
使用场景四:解决SimpleDateFormat线程不安全问题;

二、synchronized 和 ReentrantLock 都是 Java 中提供的可重入锁,二者的主要区别有以下 5 个:

1.用法不同:synchronized 可以用来修饰普通方法、静态方法和代码块,而 ReentrantLock 只能用于代码块。
2.获取锁和释放锁的机制不同:synchronized 是自动加锁和释放锁的,而 ReentrantLock 需要手动加锁和释放锁。
3.锁类型不同:synchronized 是非公平锁,而 ReentrantLock 默认为非公平锁,也可以手动指定为公平锁。
4.响应中断不同:ReentrantLock 可以响应中断,解决死锁的问题,而 synchronized 不能响应中断。
5.底层实现不同:synchronized 是 JVM 层面通过监视器实现的,而 ReentrantLock 是基于 AQS 实现的。

三、线程安全的集合类有哪些?

Vector:Vector是一个可变长度的数组,它会给几乎所有的public方法都加上synchronized关键字。但由于加锁会导致性能降低到一定程度。
HashTable:
CopyOnWriteArrayList 适合读多写少的场景,写多的情况下,频繁地加锁和复制,也是一笔很大的开销。
ConcurrentHashMap:
Collections针对了各种集合来声明了一个线程安全的包装类,它在原集合的基础上添加了锁对象,这样就使得集合中的每个方法都能够通过这个锁对象来实现同步。

四、说一下你对CompletableFuture的理解

CompletableFuture是JDK1.8里面引入的一个基于事件驱动的异步回调类。
简单来说,就是当使用异步线程去执行一个任务的时候,我们希望在任务结束以后触发一个后续的动作。 可以将多个异步任务串联起来,组成一个完整的链式调用。
比如说。我们做数据挖掘分析时,先把前端传过来的数据入库,再调用R语言函数获取分析结果,再返回给前端,调用R语言函数可能设计到多个接口。故使用CompletableFuture 开启一个异步任务。执行完后异步触发其他接口的调用

CompletableFuture 与 Future 区别:
Future 在实际使用过程中存在一些局限性,例如不支持异步任务的编排组合、获取计算结果的 get() 方法为阻塞调用等

四、项目中是如何创建线程池的,为什么不用Executors 去创建线程池

引用阿里巴巴Java开发手册上的一句话

【强制】线程池不允许使用 Executors 去创建,而是通过 ThreadPoolExecutor 的方式,这样 的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险。
说明:Executors 返回的线程池对象的弊端如下:
1)FixedThreadPool 和 SingleThreadPool: 允许的请求队列长度为 Integer.MAX_VALUE,可能会堆积大量的请求,从而导致 OOM。
2)CachedThreadPool和 ScheduledThreadPool: 允许的创建线程数量为 Integer.MAX_VALUE,可能会创建大量的线程,从而导致 OOM。

通过Executors创建一个定长线程池,示例(不要使用)

ExecutorService fixedThreadPool = Executors.newFixedThreadPool(5);

严格来说,使用此代码创建线程池时,是不符合编程规范的。

因为主要问题是定长线程池允许的请求队列长度为 Integer.MAX_VALUE,堆积的请求处理队列可能会耗费非常大的内存,甚至OOM。

通过手动调用ThreadPoolExecutor去创建线程池
比如我们在Executors.newFixedThreadPool基础上给LinkedBlockingQueue加一个容量,当队列已经满了,而仍需要添加新的请求会抛出相应异常,我们可以根据异常做相应处理。

public static ExecutorService newFixedThreadPool(int nThreads) {
    return new ThreadPoolExecutor(nThreads, nThreads,
                                  0L, TimeUnit.MILLISECONDS,
                                  new LinkedBlockingQueue<Runnable>(10)); //添加容量大小
}

六、ThreadPoolExecutor 参数说明

在这里插入图片描述

在这里插入图片描述
线程池的重要执行节点:

  1. 当任务来了之后,判断线程池中实际线程数是否小于核心线程数,如果小于就直接创建并执行任务。
  2. 当实际线程数大于核心线程数(正式员工),他就会判断任务队列是否已满,如果未满就将任务存放队列即可。
  3. 判断线程池的实际线程数是否大于最大线程数(正式员工 + 临时员工),如果小于最大线程数,直接创建线程执行任务;实际线程数已经等于最大线程数,则会直接执行拒绝策略。

拒绝策略
(4种 JDK 提供的拒绝策略 + 1 种 自定义拒绝策略)
在这里插入图片描述
线程状态

  1. RUNNING:这个没什么好说的,这是最正常的状态:接受新的任务,处理等待队列中的任务;
    SHUTDOWN:不接受新的任务提交,但是会继续处理等待队列中的任务;

  2. STOP:不接受新的任务提交,不再处理等待队列中的任务,中断正在执⾏任务的线程;

  3. TIDYING:所有的任务都销毁了,workCount 为 0。线程池的状态在转换为 TIDYING 状态时,会执 ⾏钩⼦⽅法 terminated();

  4. TERMINATED:terminated() ⽅法结束后,线程池的状态就会变成这个。
    原文链接:https://blog.csdn.net/m0_48273471/article/details/124171220

总结

提示:这里对文章进行总结:

例如:以上就是今天要讲的内容,本文仅仅简单介绍了pandas的使用,而pandas提供了大量能使我们快速便捷地处理数据的函数和方法。

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

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

相关文章

R语言生物群落(生态)数据统计分析与绘图(从数据整理到分析结果展示)

R 语言作的开源、自由、免费等特点使其广泛应用于生物群落数据统计分析。生物群落数据多样而复杂&#xff0c;涉及众多统计分析方法。以生物群落数据分析中的最常用的统计方法回归和混合效应模型、多元统计分析技术及结构方程等数量分析方法为主线&#xff0c;通过多个来自经典…

C++类和对象三

文章目录 类和对象三初始化列表用途与特性 explicit关键字再谈构造函数static成员static的特性 友元友元函数友元函数特性 友元类友元类特性 内部类概念特性 匿名对象拷贝对象时的一些编译器优化 类和对象三 初始化列表 初始化列表&#xff1a;以一个冒号开始&#xff0c;接着…

【源码解析】Spring Bean生命周期源码解析

Spring启动核心 AbstractApplicationContext#refresh&#xff0c;Spring刷新容器的核心方法。最关键的就是 AbstractApplicationContext#invokeBeanFactoryPostProcessors&#xff0c;扫描BeanAbstractApplicationContext#finishBeanFactoryInitialization&#xff0c;生成Be…

【MySql】InnoDB一棵B+树可以存放多少行数据?

文章目录 背景一、怎么得到InnoDB主键索引B树的高度&#xff1f;二、小结三、最后回顾一道面试题总结参考资料 背景 InnoDB一棵B树可以存放多少行数据&#xff1f;这个问题的简单回答是&#xff1a;约2千万。为什么是这么多呢&#xff1f;因为这是可以算出来的&#xff0c;要搞…

[C语言实现]带你手撕带头循环双链表

目录 什么是双链表&#xff1f; 带头结点的优势: 双链表的实现: 什么是循环双链表&#xff1f; 众所周知&#xff0c;顺序表的插入和删除有时候需要大量移动数据&#xff0c;并且每次开辟空间都可能会浪费大量内存和CPU资源&#xff0c;于是我们有了链表&#xff0c;我们之…

【实用篇】SpringCloud01

SpringCloud01 1.认识微服务 随着互联网行业的发展&#xff0c;对服务的要求也越来越高&#xff0c;服务架构也从单体架构逐渐演变为现在流行的微服务架构。这些架构之间有怎样的差别呢&#xff1f; 1.0.学习目标 了解微服务架构的优缺点 1.1.单体架构 单体架构&#xff…

基于复旦微 JFM7K325T 全国产FPGA的高速数据采集、图像处理方案

板卡概述 PCIE-XM711 是一款基于 PCIE 总线架构的高性能数据预处理 FMC载板&#xff0c;板卡采用复旦微的 JFM7K325T FPGA 作为实时处理器&#xff0c;实现 各个接口之间的互联。该板卡可以实现 100%国产化。 板卡具有 1 个 FMC&#xff08;HPC&#xff09;接口&#xff0c;1 路…

这10道测试用例面试题,面试官肯定会问到

前言 软件测试面试中&#xff0c;测试用例是非常容被问到的一个点&#xff0c;今天小编就给大家把最常见的测试用例方面的问题给大家整理出来&#xff0c;希望对大家的面试提供帮助。 1、 什么是测试用例‍ 答&#xff1a;测试用例的设计就是如何覆盖所有软件表现出来的状态…

硬盘有多少图片取决我的网速, Python获取硬盘少女图集

目录 前言开发环境:案例实现的步骤:代码展示尾语 &#x1f49d; 前言 嗨喽~大家好呀&#xff0c;这里是魔王呐 ❤ ~! 图片数据在网络中随处可见, 如果需要一些图片素材 一睹为快把! ! ! 开发环境: 解释器: python 3.8 编辑器: pycharm 2022.3 专业版 内置模块使用 os &g…

CH341的I2C接口编程说明

CH341的I2C接口特性&#xff1a; 1、支持I2C速度20K/100K/400K/750K&#xff1b; 2、默认不支持设备的ACK应答监测&#xff0c;即忽略ACK状态&#xff1b;强制支持需修改软件&#xff1b; 引脚序号功能说明24SCL23SDA Windows系统SPI通讯接口函数 HANDLE WINAPI CH341OpenD…

Piccolo傻瓜式环境配置

首先下载Piccolo的代码 Piccolo下载网址点击Code然后点击Download ZIP。可能有点慢&#xff0c;总共要下139M。 下载CMAKE CMAKE下载网址下载完后安装CMAKE 构建环境 将下来的Piccolo-main压缩包解压为Piccolo-main文件夹。打开CMAKE&#xff0c;如下图进行目录选择&…

Linux - 第19节 - 网络基础(传输层二)

1.TCP相关实验 1.1.理解listen的第二个参数 在编写TCP套接字的服务器代码时&#xff0c;在进行了套接字的创建和绑定之后&#xff0c;需要调用listen函数将创建的套接字设置为监听状态&#xff0c;此后服务器就可以调用accept函数获取建立好的连接了。其中listen函数的第一个参…

LeetCode - 1049 最后一块石头的重量 II (0-1背包)

欢迎关注我的CSDN:https://spike.blog.csdn.net/ 本文地址:https://blog.csdn.net/caroline_wendy/article/details/130935119 LeetCode:1049. 最后一块石头的重量 II 题目:有一堆石头,用整数数组 stones 表示。其中 stones[i] 表示第 i 块石头的重量。 每一回合,从中选…

人脸识别3:C/C++ InsightFace实现人脸识别Face Recognition(含源码)

人脸识别3&#xff1a;C/C InsightFace实现人脸识别Face Recognition(含源码) 目录 1. 前言 2. 项目安装 &#xff08;1&#xff09;项目结构 &#xff08;2&#xff09;配置开发环境(OpenCVOpenCLbase-utilsTNN) &#xff08;3&#xff09;部署TNN模型 &#xff08;4&a…

【C++】手把手教你模拟实现string类

模拟实现string 前言类的成员变量构造函数析构函数size和length[ ] 重载迭代器赋值运算符重载和拷贝构造函数拷贝构造函数赋值运算符重载现代式写法 reserve 和 resizereserveresize 字符串追加push_backappend insertpos位置插字符pos位置插字符串 erase>> 和 <<&…

Linux---用户权限(权限位、chowd、chown)

1. 权限位 序号1&#xff0c;表示文件、文件夹的权限控制信息 序号2&#xff0c;表示文件、文件夹所属用户 序号3&#xff0c;表示文件、文件夹所属用户组 权限细节总共分为10个槽位&#xff1a; 举例&#xff1a;drwxr-xr-x&#xff0c;表示&#xff1a; 这是一个文件夹&…

如何使用Metasploit进行后渗透攻击?

后渗透攻击&#xff08;PostExploitation&#xff09;是整个渗透测试过程中最能够体现渗透测试团队创造力与技术能力的环节。前面的环节可以说都是在按部就班地完成非常普遍的目标&#xff0c;而在这个环节中&#xff0c;需要渗透测试团队根据目标组织的业务经营模式、保护资产…

关于PyQt5的环境搭建

目录 一、需要的环境 二、安装python 1、python安装链接 三、安装PyQt5 1、使用豆瓣的镜像 2、配置环境变量 四、安装pycharm 1、pycharm官网链接 五、配置环境 1、找到设置 2、添加designer 3、配置ui 4、配置rc 六、注意问题 一、需要的环境 1、安装好python安装…