JUC并发编程学习笔记(一)——知识补充(Threadlocal和引用类型)

news2024/12/27 11:15:01

强引用、弱引用、软引用、虚引用

Java执行 GC(垃圾回收)判断对象是否存活有两种方式,分别是引用计数法引用链法(可达性分析法)

**引用计数:**Java堆中给每个对象都有一个引用计数器,每当某个对象在其它地方被引用时,该对象的计数器 +1;引用失效则 -1;

JDK 1.2版本开始,对象的引用被划分为 4种级别,使程序能更加灵活地控制对象的生命周期。这 4种级别由高到低依次为:强引用软引用弱引用虚引用

强引用(StrongReference)

在一个线程内,无须引用直接可以使用的对象,强引用不会被JVM清理。我们平时申明变量使用的就是强引用,普通系统99%以上都是强引 用,比如,String s="Hello World"。

Java中的引用,有点像 C++的指针。通过引用,可以对堆中的对象进行操作。在Java 程序中,最常见的引用类型是强引用,它也是默认的引用类型。例如:StringBuffer str=new StringBuffer(“Hello World”);

强引用具备以下特点
**(1)**强引用可以直接访问目标对象。
**(2)**强引用所指向的对象在任何时候都不会被系统回收。JVM宁愿抛出Out Of Memory异常也不会回收强引用所指向的对象。
**(3)**强引用可能导致内存泄漏。

通常来说,应用程序内部的内存泄露两种情况。一种是虚拟机中存在程序无法使用的内存区域,另一种情况是程序中存在大量存活时间过长的对象。

(二) 软引用(SoftReference)

java中使用SoftRefence来表示软引用

软引用是除了强引用外最强的引用类型,我们可以通过java.lang.ref.SoftReference使用软引用。一个持有软引用的对象,它不会被JVM很快回收,JVM会根据当前堆的使用情况来判断何时回收。当堆使用率临近阙值时,才会去回收软引用的对象。只要有足够的内存,软引用便可能在内存中存活相当长一段时间。通过软引用,垃圾回收器就可以在内存不足时释放软引用可达的对象所占的内存空间。保证程序正常工作。
通过一个软引用申明,JVM抛出OOM之前,清理所有的软引用对象。垃圾回收器某个时刻决定回收软可达的对象的时候,会清理软引用,并可选的把引用存放到一个引用队列(ReferenceQueue)。

(三) 弱引用(WeakReference)

java中使用WeakReference来表示弱引用。如果某个对象与弱引用关联,那么当JVM在进行垃圾回收时,无论内存是否充足,都会回收此类对象。

通过一个弱引用申明。类似弱引用,只不过 Java 虚拟机会尽量让软引用的存活时间长一些,迫不得已才清理。

(四) 虚引用(PhantomReference)

java中使用PhantomReference来表示虚引用。

通过一个虚引用申明。仅用来处理资源的清理问题,比Object里面的finalize机制更灵活。get方法返回的永远是null,Java虚拟机不负责清理虚引用,但是它会把虚引用放到引用队列里面

Java中 4种引用的级别和强度由高到低依次为:强引用 -> 软引用 -> 弱引用 -> 虚引用

垃圾回收器回收时,某些对象会被回收,某些不会被回收。垃圾回收器会从根对象 Object来标记存活的对象,然后将某些不可达的对象和一些引用的对象进行回收。

在这里插入图片描述

ThreadLocal

1. 简介

ThreadLocal叫做线程变量,意思是ThreadLocal中填充的变量属于当前线程,该变量对其他线程而言是隔离的,也就是说该变量是当前线程独有的变量。ThreadLocal为变量在每个线程中都创建了一个副本,那么每个线程可以访问自己内部的副本变量。

ThreadLoal 变量,线程局部变量,同一个 ThreadLocal 所包含的对象,在不同的 Thread 中有不同的副本。这里有几点需要注意:

  • 因为每个 Thread 内有自己的实例副本,且该副本只能由当前 Thread 使用。这是也是 ThreadLocal 命名的由来。
  • 既然每个 Thread 有自己的实例副本,且其它 Thread 不可访问,那就不存在多线程间共享的问题

ThreadLocal 提供了线程本地的实例。它与普通变量的区别在于,每个使用该变量的线程都会初始化一个完全独立的实例副本。ThreadLocal 变量通常被private static修饰。当一个线程结束时,它所使用的所有 ThreadLocal 相对的实例副本都可被回收。

总的来说,ThreadLocal 适用于每个线程需要自己独立的实例且该实例需要在多个方法中被使用,也即变量在线程间隔离而在方法或类间共享的场景

在这里插入图片描述

2. ThreadLocal与Synchronized的区别

ThreadLocal其实是与线程绑定的一个变量。ThreadLocal和Synchonized都用于解决多线程并发访问。

但是ThreadLocal与synchronized有本质的区别:

  1. Synchronized用于线程间的数据共享,而ThreadLocal则用于线程间的数据隔离。
  2. Synchronized是利用锁的机制,使变量或代码块在某一时该只能被一个线程访问。而ThreadLocal为每一个线程都提供了变量的副本,使得每个线程在某一时间访问到的并不是同一个对象,这样就隔离了多个线程对数据的数据共享。
  3. 而Synchronized却正好相反,它用于在多个线程间通信时能够获得数据共享。

2.1 一句话概括

一句话理解ThreadLocal,threadlocl是作为当前线程中属性ThreadLocalMap集合中的某一个Entry的key值Entry(threadlocl,value),虽然不同的线程之间threadlocal这个key值是一样,但是不同的线程所拥有的ThreadLocalMap是独一无二的,也就是不同的线程间同一个ThreadLocal(key)对应存储的值(value)不一样,从而到达了线程间变量隔离的目的,但是在同一个线程中这个value变量地址是一样的。

3. ThreadLocal 常见使用场景

如上文所述,ThreadLocal 适用于如下两种场景

  • 每个线程需要有自己单独的实例
  • 实例需要在多个方法中共享,但不希望被多线程共享

对于第一点,每个线程拥有自己实例,实现它的方式很多。例如可以在线程内部构建一个单独的实例。ThreadLocal 可以以非常方便的形式满足该需求。

对于第二点,可以在满足第一点(每个线程有自己的实例)的条件下,通过方法间引用传递的形式实现。ThreadLocal 使得代码耦合度更低,且实现更优雅。

4. 总结

前文我们讲过ThreadLocal的主要用途是实现线程间变量的隔离,表面上他们使用的是同一个ThreadLocal, 但是实际上使用的值value却是自己独有的一份。用一图直接表示threadlocal 的使用方式。

在这里插入图片描述

从图中我们可以当线程使用threadlocal 时,是将threadlocal当做当前线程thread的属性ThreadLocalMap 中的一个Entry的key值,实际上存放的变量是Entry的value值,我们实际要使用的值是value值。value值为什么不存在并发问题呢,因为它只有一个线程能访问,不存在资源竞争.

Entry将ThreadLocal作为Key,值作为value保存,它继承自WeakReference,注意构造函数里的第一行代码super(k),这意味着ThreadLocal对象是一个「弱引用」。可以看图1.

key是弱引用,而value是强引用,弱引用随着程序的运行会被垃圾回收掉,而强引用不会;

4.1 ThreadLocal使用注意点

  • 避免读取到脏数据

    现在代码中比较常见的使用到了线程池,线程池中的线程是可重复利用的,假设使用ThreadLocal 设置了value值,如果没有进行remove操作,下次该线程又被取到,通过get方法取到的值是上次设置的value值

    处理方式: 使用完后进行remove操作。

  • 避免内存泄漏

    使用了线程池后,由于线程一直存在, 对应的value值就不能被垃圾回收掉,容易产生内存泄漏问题。

    由于ThreadLocalMap 的生命周期跟 Thread 一样长,对于重复利用的线程来说,如果没有手动删除(remove()方法)对应 key 就会导致entry(null,value)的对象越来越多,从而导致内存泄漏.

    处理方式: 使用完后进行remove操作。

  • 将ThreadLocal变量定义成private static的,这样的话ThreadLocal的生命周期就更长,由于一直存在ThreadLocal的强引用,所以ThreadLocal也就不会被回收,也就能保证任何时候都能根据ThreadLocal的弱引用访问到Entry的value值,然后remove它,防止内存泄露。
    cal的生命周期就更长,由于一直存在ThreadLocal的强引用,所以ThreadLocal也就不会被回收,也就能保证任何时候都能根据ThreadLocal的弱引用访问到Entry的value值,然后remove它,防止内存泄露。

4.2 具体使用场景

  1. 存储用户登录Token

  2. 场景二、数据库连接,处理数据库事务

  3. 场景三、数据跨层传递(controller,service, dao)

  4. 场景四、Spring使用ThreadLocal解决线程安全问题

    我们知道在一般情况下,只有无状态的Bean才可以在多线程环境下共享,在Spring中,绝大部分Bean都可以声明为singleton作用域。就是因为Spring对一些Bean(如RequestContextHolder、TransactionSynchronizationManager、LocaleContextHolder等)中非线程安全的“状态性对象”采用ThreadLocal进行封装,让它们也成为线程安全的“状态性对象”,因此有状态的Bean就能够以singleton的方式在多线程中正常工作了

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

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

相关文章

文献阅读:Scaling Instruction-Finetuned Language Models

文献阅读:Scaling Instruction-Finetuned Language Models 1. 文章简介2. 实验 1. 数据集 & 模型 1. 数据集考察2. 使用模型 2. scale up对模型效果的影响3. CoT对模型效果的影响4. 不同模型下Flan的影响5. 开放接口人工标注指标 3. 结论 文献链接:…

【C++】类和对象(一)

目录一、面向过程和面向对象初步认识二、类的引入三、类的定义四、类的访问限定符及封装4.1、访问限定符4.2、封装五、类的作用域六、类的实例化七、类对象的大小八、this指针8.1、this指针的引出8.2、this指针的特性8.3、C语言和C实现Stack的对比一、面向过程和面向对象初步认…

XSS漏洞,通过XSS实现网页挂马

**今天讲下通过XSS实现网页挂马~*,目的是了解安全方面知识,提升生活网络中辨别度 原理: 实验分为两部分: 1、通过Kali linux,利用MS14_064漏洞,制作一个木马服务器。存在该漏洞的用户一旦通过浏览器访问木…

C语言(C文件处理函数和文件指针)

C语言有很多文件操作函数,这里我们挑了一些重要的开始讲,首先说下这些函数都定义在stdio.h头文件中 目录 一.文件指针 二.文件处理函数 1.fopen(打开文件) 2.fclose(关闭文件) 3.getc和putc(从文件指针读取字符) 4.I/O工作…

「C++控制台生存游戏」暗黑体素 DarkVoxel 控制台版

“《只有作者能看懂的一款游戏》” 刚进高中前开始写的一款抽象的生存游戏 BUG很多请见谅 ###【点击此处,免费畅玩】### 类似泰拉瑞亚的一款游戏 『暗黑体素 DarkVoxel』 直接上图! 用控制台写出如此奇葩的生存游戏,可谓世间少有。 操作…

2022黑马Redis跟学笔记.实战篇(二)

2022黑马Redis跟学笔记.实战篇 二实战篇Redis开篇导读4.1短信登录4.1.1. 搭建黑马点评项目一、导入黑马点评项目二、导入SQL三、有关当前模型四、导入后端项目相关依赖配置redis和mysql连接项目组成概述关闭Linux防火墙五、导入前端工程六、 运行前端项目4.1.2. 基于Session实现…

选购交换机的参数依据和主要的参数指标详解

如何选购交换机?用什么交换机?在选购交换机时交换机的优劣无疑十分的重要,而交换机的优劣要从总体构架、性能和功能三方面入手。交换机选购时。性能方面除了要满足RFC2544建议的基本标准,即吞吐量、时延、丢包率外,随着…

网络是怎么连接笔记(一)WEB浏览器

文章目录介绍生成HTTP请求消息向DNS服务器查询WEB服务的IP地址全世界DNS服务器的大接力委托协议栈发送消息介绍 互联网整个消息传递流程 生成HTTP请求消息向DNS服务器查询WEB服务的IP地址然后DNS服务器进行查询IP地址委托协议给对应IP发送消息 生成HTTP请求消息 整个网络发…

Spring面试重点(三)——AOP循环依赖

Spring面试重点 AOP 前置通知(Before):在⽬标⽅法运行之前运行;后置通知(After):在⽬标⽅法运行结束之后运行;返回通知(AfterReturning):在⽬标…

2023年前端面试知识点总结(CSS篇)

近期整理了一下高频的前端面试题,分享给大家一起来学习。如有问题,欢迎指正! 1. 对CSS盒模型的理解 CSS3的盒模型有两种盒子模型:标准盒子模型、IE盒子模型 盒模型都是由四个部分组成的,分别是content(内容…

layui框架学习(6:基础菜单)

菜单是应用系统的必备元素,虽然网页中的导航也能作为菜单使用,但菜单和导航的样式和用途有所不同(不同之处详见参考文献5)。Layui中用不同的预设类定义菜单和导航的样式,同时二者依赖的模块也不一样。本文主要学习和记…

Vue (3)

文章目录1. 数据代理1.1 回顾1.2 开始2. 事件处理2.1 v-on:click 点击事件2.2 事件修饰符2.3 键盘事件3. 计算属性3.1 插值语法实现3.2 methods实现3.3 计算属性实现4. 监视属性4.1 深度监视4.2 监视属性的简写形式4.3 watch 与 computed 对比1. 数据代理 在学习 数据代理 时 先…

SQL数据查询——单表查询和排序

文章目录一、单表查询1.查询列1)查询全部列指定列2)查询经过计算的值3)列的别名2.查询元组1)消除取值重复的行(DISTINCT)2)条件查询(WHERE)3.空值参与运算4.着重号二、排序(ORDER BY子句)一、单表查询 单表查询指仅涉及…

Webpack的知识要点

在前端开发中,一般情况下都使用 npm 和 webpack。   npm是一个非常流行的包管理工具,帮助开发者管理项目中使用的依赖库和工具。它可以方便地为项目安装第三方库,并在项目开发过程中进行版本控制。   webpack是一个模块打包工具&#xff…

C语言深度剖析之程序环境和预处理

1.程序的翻译环境和执行环境 第一种是翻译环境,在这个环境中源代码被转换为可执行的机器指令 第二种是执行环境,它用于实际执行代码 2.翻译环境 分为四个阶段 预编译阶段 ,编译,汇编,链接 程序编译过程:多个…

使用vue3,vite,less,flask,python从零开始学习硅谷外卖(16-40集)

严正声明! 重要的事情说一遍,本文章仅供分享,文章和代码都是开源的,严禁以此牟利,严禁侵犯尚硅谷原作视频的任何权益,我知道学习编程的人各种各样的心思都有,但这不是你对开源社区侵权的理由&am…

iptables防火墙之SNAT与DNAT

目录 1、SNAT策略概述 1.SNAT策略的典型应用环境 2.SNAT策略的原理 3.SNAT工作原理 4.SNAT转换前提条件 5.开启SNAT命令 6.SNAT转换 2.SNAT示例 1. 配置网关服务器 2.Xshell 连接192.168.100.100 3.DNAT策略及应用 1. DNAT策略概述 2.DNAT 策略的应用 3.DNAT转换前提条件…

看完这篇 教你玩转渗透测试靶机vulnhub——Hack Me Please: 1

Vulnhub靶机Hack Me Please: 1渗透测试详解Vulnhub靶机介绍:Vulnhub靶机下载:Vulnhub靶机安装:Vulnhub靶机漏洞详解:①:信息收集:②:漏洞利用③:获取反弹shell:④&#x…

how https works?https工作原理

简单一句话: https http TLShttps 工作原理:HTTPS (Hypertext Transfer Protocol Secure)是一种带有安全性的通信协议,用于在互联网上传输信息。它通过使用加密来保护数据的隐私和完整性。下面是 HTTPS 的工作原理:初始化安全会…

Camtasia2023最新版电脑视频录屏记录编辑软件

在Mac或Wind上有各种可用的视频记录和编辑软件,其中Camtasia被称为视频记录器和视频编辑器。录屏软件Camtasia2023到底有什么特色功能?本文将帮助您选择理想的选择来开始视频捕获,创建和编辑。Camtasia2023是Mac/win平台上一款使用非常简单的…