![](https://img-blog.csdnimg.cn/20201014180756918.png?x-oss-process=image/resize,m_fixed,h_64,w_64)
Java
文章平均质量分 61
Java基础知识总结以及相关分析
煎丶包
这个作者很懒,什么都没留下…
展开
-
ThreadLocal从变量副本的角度解决多线程并发安全问题
ThreadLocal从变量副本的角度解决多线程并发安全问题之前我们讲的高并发场景下的线程安全问题,可以使用Synchronized同步关键字、Lock手动加锁的方式去解决,什么轻量级锁、偏向锁、重量级锁、可重入锁等等,实际上本质都是控制线程,使得多个线程同步的去访问共享资源。之所以多线程存在线程安全问题,就是因为多个线程访问同一个共享资源导致的,多个线程之间属于竞争关系,很容易就会导致数据的不安全。我们说了加锁实际上保证了各个线程之间同步、有序的去访问共享资源,难道不加锁就没有办法解决多线程安全问题原创 2021-10-03 18:56:39 · 807 阅读 · 0 评论 -
【源码】走一遍源码弄清ArrayList容器的扩容机制
【源码】走一遍源码弄清ArrayList容器的扩容机制首先我们来看看ArraysList容器在整个Java集合框架中所处的位置由此可见ArrayList是Java集合框架中,两大派系中Collection接口的子接口List的实现类我们从源码入手可以看到ArrayList底层数据结构实际上是一个**Object类型的数组**,由于Object是所有类的父类,所以ArrayList集合可以存放任意类型的元素,并且存放的元素是有序的、可重复的、可随机访问的。接下来我们就以add()方法为突破口,来解原创 2021-10-01 16:00:23 · 505 阅读 · 0 评论 -
【源码】看一看Spring如何使用三级缓存解决循环依赖问题
【源码】看一看Spring如何使用三级缓存解决循环依赖问题我们之前文章讲Bean的创建过程中,提到了如果当前bean依赖的其它bean,就会调用getBean()方法把依赖的bean先创建出来可是你有没有想过,如果当前Bean依赖于另一个Bean,而另一个Bean又就形成了依赖于当前Bean,或者当前Bean依赖于自己,这样依赖关系形成了一个闭环。这就是我们这篇文章将要说的Bean的循环依赖问题!首先我们要明确Spring不是能够解决所有情况下的循环依赖问题的,只能解决:出现循环依赖的Bean原创 2021-09-28 22:18:19 · 644 阅读 · 0 评论 -
从Spring容器刷新过程中的创建Bean阶段来说说Bean的生命周期
从Spring容器刷新过程中的创建Bean阶段来说说Bean的生命周期我们所说的Bean的生命周期指的是从Bean的创建、初始化、使用Bean、销毁的整个过程。而IOC容器就是负责管理Bean的整个生命周期。实际上Bean的生命周期在容器启动的时候就已经开始了,严格来说,你可以认为容器启动时,从注解配置读取器读取标有注解的类,转换为BeanDefinition对象时,Bean的生命周期就已经开始了。打个比方,小宝宝的生命的起点,并不是说从出生落地开始算的,而是从妈妈肚子里面,基本上可以算是生命已经开始了。原创 2021-09-28 02:56:04 · 499 阅读 · 0 评论 -
【源码】走一遍refresh()方法的源码就能弄懂Spring容器的创建过程
【源码】走一遍refresh()方法的源码就能弄懂Spring容器的创建过程Spring框架的两大核心思想,一个是IOC控制反转,另一个就是AOP面向切面编程。而IOC控制反转指的是将创建对象的操作交给Spring容器来解决,容器同一对所有的对象进行管理,我们无需关心创建对象时,对象之间的依赖关系,只需要在使用对象时从容器中获取即可。要想从容器中获取对象来使用,那就必须首先创建出这个Spring容器,这篇文章就来从源码角度出发,来看看Spring容器的创建过程。创建Bean可以使用XML配置文件,也可以原创 2021-09-27 13:17:43 · 330 阅读 · 0 评论 -
说一说JVM类加载子系统使用的各种类加载器
说一说JVM类加载子系统使用的各种类加载器之前我们在《从JVM层面谈一谈类的加载过程》这篇文章中,详细的介绍了类加载的过程。我们说一个类,从class字节码二进制数据流转化为类模板加载到系统内存中,这一过程是由类加载子系统实现的,确切的说是由类加载子系统中的各种类加载器实现的。这篇文章就来谈一谈都有哪些类加载器以及它们的作用都是什么。所有的类都是由ClassLoader进行加载的,Classloader负责通过各种方式将类信息的二进制数据流读入到JVM内部的方法区,形成一个类模板数据结构,进而转换为一个原创 2021-09-18 21:55:33 · 362 阅读 · 0 评论 -
从JVM层面谈一谈类的加载过程
从JVM层面谈一谈类的加载过程之前在Java内存区域详解(万字总结!一篇入魂!点赞收藏!)这篇文章中详细讲解了Java内存区域,我们下面再放一张图,回顾一下Java内存区域都划分为了哪几部分通过JVM整体架构来看,Java内存区域,也就是运行时数据区,是JVM的核心。我们知道Java内存区域是用来存放程序运行过程中产生的数据的区域,如果我们要向将Java程序运行起来,首先必须把编译出来class文件加载到内存中,而负责加载的就是JVM中的类加载子系统,它负责将编译好的class文件加载到内存中。这篇文原创 2021-09-17 17:24:55 · 153 阅读 · 0 评论 -
从ThreadPoolExecutor源码着手来谈一谈并发中使用的线程池
从ThreadPoolExecutor源码着手来谈一谈并发中使用的线程池线程池,关键在于一个**“池”字,你可以联想一下数据库连接池、字符串常量池等等,都是实际上都是利用池化技术**来减少每次获取资源的消耗,提高对资源的利用率。在高并发多线程的场景下,某个时间段内肯定不只有一个线程在工作,而是有大量的线程同时在执行任务。当面对大量的请求等待处理时,我们不可能一个一个的创建出线程,然后分配请求任务让这个线程去处理,这样效率也太低了。怎么解决呢?我们想如果说事先创建好了很多线程,随时待命,一旦有请求发送过来,原创 2021-09-16 17:22:25 · 187 阅读 · 0 评论 -
从Java内存模型的角度来解读volatile关键字
从Java内存模型的角度来解读volatile关键字在之前关于高并发线程同步控制的文章中,我们讲了Synchronized关键字的作用以及底层JVM的实现原理,也讲了另一把ReentrantLock可重入锁的作用及底层源码的实现。而为了保证多线程情况下线程之间的同步,除了加锁以外,还可以使用volatile关键字,它是JVM提供的一个轻量级的同步机制。首先我们要明确并发编程的3个重要特性:原子性一次操作或者多次操作,要么所有的操作全部都执行并且不会受到任何外界因素的干扰而中断,要么就全部都不执行原创 2021-09-14 20:26:50 · 169 阅读 · 0 评论 -
从AQS切入谈一谈不逊色于Synchronized的ReentrantLock可重入锁
从AQS切入谈一谈不逊色于Synchronized的ReentrantLock可重入锁之前在《结合JVM深入谈一谈Synchronized关键字的神奇之处》这篇文章中,提到了Synchronized和ReentrantLock的区别,Synchronized是依赖于JVM实现的,是JVM层面的锁,并且它的优化也是从JVM底层进行优化的。而ReentrantLock可重入锁是API层面的,ReentrantLock这个类实现了Lock这个接口,需要我们使用lock()和unlock()方法手动的进行加锁和释原创 2021-09-13 20:53:25 · 3805 阅读 · 0 评论 -
Java垃圾回收机制详解(万字总结!一篇入魂!)
Java垃圾回收机制详解之前在《Java内存区域详解》这篇文章中,详细介绍了JVM内存区域的划分,以及创建对象时内存的分配情况。Java的自动内存管理机制,除了自动申请内存还会自动释放内存,这篇文章就来说一说Java内存回收机制。首先我们要明确几点,问什么要回收内存?哪些内存是需要回收的?什么时候回收?应该怎样回收?(Why?What?When?How?)举个例子,垃圾桶,你平时制造出来的垃圾都随手扔到了垃圾桶里,这垃圾桶就好比堆空间,你扔进去一个垃圾,就好比在堆空间自动申请的一块内存来存放这个垃圾,原创 2021-09-08 10:56:33 · 2397 阅读 · 0 评论 -
扒一扒HashMap和ConcurrentHashMap的本质(万字总结!一篇入魂!)
扒一扒HashMap和ConcurrentHashMap的本质Java集合,或者说Java容器,可以分为两大派系,一类是实现了Collection接口的容器,另一类是实现了Map接口的容器。这篇文章要将的就是实现了Map接口的HashMap集合。先来看一下Map接口整体的框架HashMapHashMap集合是线程不安全的,在JDK 8 之前HashMap是由数组+链表组成的,数组是HashMap的主体部分,链表则是主要为了解决hash冲突而存在的,主要是采用拉链法解决冲突。到了JDK 8及以后原创 2021-09-06 10:10:02 · 230 阅读 · 0 评论 -
Java内存区域详解(万字总结!一篇入魂!点赞收藏!)
Java内存区域详解JVM自动内存管理机制,可以使得不像C/C++语言那样,需要手动的申请和释放内存,Java将内存的申请和释放完全交给JVM来管理,所以并不容易出现内存泄漏和内存溢出的问题。但是并不代表不会发生,所以我们必须要熟悉JVM,要熟悉JVM自动内存管理的机制,这样我们在发生内存问题时,才知道该如何下手去解决。JVM在运行时会把管理的内存划分为不同的数据区域,包括线程共享的堆、方法区,以及线程私有的虚拟机栈、本地方法栈、程序计数器。一共五大部分。但是在JDK 8前后,内存区域的划分出现了变动,原创 2021-09-04 15:27:44 · 1022 阅读 · 0 评论 -
JMM详解与volatile关键字
一、Java内存模型——JMMJMM本身是一种抽象的概念,并不真实存在,它描述的是一组规则或者规范,就想JVM一样通过JMM规范定义了程序中各个变量(包括实例字段、静态字段和构成数组对象的元素)的访问方式JMM的可见性、原子性、有序性使得线程安全得到保证其中JMM对同步做出了规定:线程加锁前,必须读取主内存的最新值到自己的工作内存线程解锁前,必须把共享变量的值刷新回主内存加锁解锁必须是同一把锁由于JVM运行程序的实体是线程,而每个线程创建时JVM都会为其创建一个工作内存,工作内存是每个线原创 2021-08-10 15:45:53 · 163 阅读 · 0 评论 -
字符串方法intern()详解
一、intern()方法运行时常量池是方法区的一部分,在JDK 8的时候,方法区概念的落地实现由永久代变成了元空间intern()方法的源代码如下图所示intern()方法是一个本地方法调用该方法时,如果字符串常量池中已经存在一个等于此String对象的字符串,就直接从常量池中返回这个字符串对象的引用如果调用该方法的这个字符串对象,目前字符串常量池中还并不存在这个字符串对象,也就是说这个字符串对象是首次出现的,那么就新建并添加这个字符串对象到字符串常量池中,并返回新建的字符串对象的引用二、原创 2021-08-09 10:59:47 · 7809 阅读 · 3 评论 -
【Go语言实现JVM】根据Java命令编写命令行工具
一、Java应用程序运行命令Java应用程序需要有一个入口,而这个入口就是main()方法,包含main()方法的这个Java类叫作主类。JVM规范并没有规定哪个类是主类,所以我们可以自己创建一个主类,只要包含main()方法即可。虽然我们可以自定义一个主类,但是如何告诉JVM哪个类是主类呢?实际上JVM是通过java命令来加载并启动主类,主类名可以由命令行参数指定我们在cmd命令窗口执行java命令从回显中可以看到java命令的具体用法java [-options] class [args原创 2021-08-01 21:15:08 · 1624 阅读 · 1 评论 -
从字节码角度分析i++与++i以及i+=1与i=i+1运算操作
变量的自增操作,如i++++ii+=1i=i++这些自增操作的算术运算可能计算的最后结果是一样,仅从代码层面很难看出它们的异同。下面将从字节码指令的角度去分析这些操作的不同之处。i++与++i的区别如果只是进行变量的自增的运算,不涉及赋值操作,那么i++和++i在字节码指令层面上是执行相同的指令可以看出i++与++i的字节码指令是一样的,都是先将操作数10压入操作数栈,然后保存到局部变量表索引为1的位置,也就是保存变量i的位置,然后将局部变量表索引为1的位置的变量的值加1。但是如果原创 2021-07-29 18:10:07 · 2560 阅读 · 0 评论 -
运行时数据区——方法区
一、栈、堆、方法区的交互关系变量名存放在栈帧的局部变量表中,创建出来的对象实例数据存放在堆中,对象类型的具体数据则存放在方法区。同属对象实例中维护一个指向对象类型的指针,用于获取该对象实例的类型数据。二、方法区方法区在逻辑上是属于堆的一部分,但是方法区可以看作是一块独立于Java堆的内存空间方法区与堆一样,是各个线程共享的内存区域方法区在JVM启动的时候被创建,并且它的实际的物理内存空间中和Java堆区一样都可以是不连续的方法区的大小,跟堆空间一样,可以选择固定大小或者可扩展方法区的大原创 2021-07-22 10:14:09 · 161 阅读 · 0 评论 -
运行时数据区——堆
一、堆的概述一个进程对应一个JVM实例,也就是一个进程对应一个运行时数据区。一个进程又包含多个线程,这些线程共享了方法区和堆,但是每个线程都有各自的程序计数器、本地方法栈和虚拟机栈。一个jvm实例只存在一个堆内存,堆也是java内存管理的核心区域Java堆区在JVM启动的时候即被创建,其空间大小也就确定了,是JVM管理的最大一块内存空间堆可以处于物理上不连续的内存空间中,但在逻辑上它应该被视为连续的所有的线程共享java堆,在这里还可以划分线程私有的缓冲区(TLAB),所以堆空间不一定是所有线程原创 2021-07-20 11:31:27 · 280 阅读 · 0 评论 -
运行时数据区——本地方法栈
本地方法栈Java虚拟机栈用于管理Java方法的调用,而本地方法栈用于管理本地方法的调用本地方法栈,也是线程私有的。允许被实现成固定或者是可动态扩展的内存大小。如果线程请求分配的栈容量超过本地方法栈允许的最大容量,Java虚拟机将会抛出一个StackOverFlowError异常。如果本地方法栈可以动态扩展,并且在尝试扩展的时候无法申请到足够的内存,或者在创建新的线程时没有足够的内存去创建对应的本地方法栈,那么java虚拟机将会抛出一个OutOfMemoryError异常。本地方法是原创 2021-07-19 08:54:48 · 77 阅读 · 0 评论 -
运行时数据区——Java虚拟机栈
一、Java虚拟机栈每个线程在创建时都会创建一个虚拟机栈,其内部保存一个个的栈帧,每一个栈帧对于一个方法Java虚拟机栈是线程私有的Java虚拟机栈的生命周期和线程一致虚拟机栈主要管理程序的运行,保存方法的局部变量、部分结果,并参与方法的调用和返回二、栈的优势栈是一种快速有效的分配存储方式,访问速度仅次于程序计数器JVM操作栈,当方法执行时,执行入栈操作,当方法结束时,执行出栈操作栈不存在垃圾回收问题,但是存在栈溢出问题三、栈的存储单位每个线程都有自己的栈,栈中的数据都是以栈原创 2021-07-18 22:41:29 · 2932 阅读 · 5 评论 -
运行时数据区——程序计数器
PC寄存器PC寄存器是用来存储指向下一条指令的地址,也就是即将要执行的指令代码,由执行引擎读取下一条指令PC寄存器是一块很小的内存空间,也是运行速度最快的存储区域每个线程都有自己的程序计数器,是线程私有的,程序计数器的生命周期与线程的生命周期保持一致任何时间一个线程都只有一个方法在执行,也就是所谓的当前方法。程序计数器会存储当前线程正在执行的Java方法的JVM指令地址,但是如果正在执行native方法,则是未指定值(undefined)程序计数器是程序控制流的指示器,分支、循环、跳转、异常处原创 2021-07-18 14:52:47 · 141 阅读 · 0 评论 -
双亲委派机制
一、双亲委派机制Java虚拟机对class文件采用的是按需加载的方式,也就是说当需要使用该类时才会将它的class文件加载到内存生成class对象。而且加载某个类的class文件时,Java虚拟机采用的是双亲委派机制,即把请求交给父类处理,它是一种任务委派模式。二、工作原理如果一个类加载器收到了类加载的请求,它并不会自己先去加载,而是把这个请求委托给父类的加载器去执行如果父类加载器还存在其父类加载器,则会进一步向上委托,依次递归请求,最终请求将到达顶层的启动类加载器如果父类加载器可以完成类加载原创 2021-07-18 10:16:29 · 139 阅读 · 0 评论 -
类加载器的分类
类加载器的分类引导类加载器(BootStrap ClassLoader)和自定义类加载器(User-Defined ClassLoader)获取每一个不同的类加载器原创 2021-07-18 09:17:38 · 172 阅读 · 0 评论 -
类加载器与类的加载过程
一、类加载器子系统类加载器子系统分为加载阶段、链接阶段、初始化阶段类加载器子系统负责从文件系统或者网络中加载class文件,class文件在文件开头有特定的文件标识ClassLoader只负责class文件的加载,class文件是否能运行,则由执行引擎决定加载的类信息存放在一块称为方法区的内存空间,除了类的信息外,方法区还会存放运行时常量池信息,可能还包含字符串字面量和数字常量(这部分常量信息是class文件中常量池部分的内存映射)二、类的加载过程1、Loading加载阶段通过一个类原创 2021-07-14 20:06:02 · 168 阅读 · 1 评论 -
JVM的生命周期
一、虚拟机的启动Java虚拟机的启动是通过引导类加载器(bootstrap class loader)创建一个初始类(initial class)来完成的,这个类是由虚拟机的具体实现指定的二、虚拟机的执行Java虚拟机的任务就是执行Java程序程序开始执行时虚拟机才运行,程序结束时虚拟机就停止执行一个Java程序,实际上执行的是一个Java虚拟机的进程三、虚拟机的退出以下几种情况会导致虚拟机的退出:程序正常执行结束程序在执行过程中遇到了异常或错误而异常终止由于操作系统用现错误而导致原创 2021-07-14 17:26:06 · 95 阅读 · 0 评论 -
单例设计模式常见形式
单例模式单例设计模式,即某个类在整个系统中只能有一个实例对象,例如JVM运行环境的Runtime类就是单例要想保证一个类只有一个实例,通过将构造器私有化来实现这个类还必须通过构造器自行创建这个实例,可以用该类的静态变量来保存这个唯一的实例通过直接暴露或者get方法获取静态变量的方式对外提供获取该实例对象常见形式饿汉式:在类初始化的时候直接创建对象,不存在线程安全问题直接实例化饿汉式public class Singleton { //内存自行创建实例对象,使用静态变量保存原创 2021-07-11 20:47:29 · 115 阅读 · 0 评论 -
使用Jedis连接redis数据库
一、测试联通Linux中启动redis服务器注意要将redis.conf配置文件中的protected-mode设置为no,同时将bind 127.0.0.1 -::1给注释掉,这样使用使用Jedis才可以从Windows访问Linux启动的redis服务器。java代码import redis.clients.jedis.Jedis;public class RedisTest { public static void main(String[] args) { Je原创 2021-05-16 16:28:37 · 381 阅读 · 1 评论 -
Maven的部署及使用
一、Maven的常用命令mvn compile执行这个命令会生成target目录,里面存放有java源代码编译后的.class文件,target目录用来存放构建的结果mvn test-compile执行这个命令会在target目录里面生成test-classes子目录,用来存放测试程序编译后的.class文件mvn packagemvn clean执行清除命令,清除target目录mvn install安装Maven工程到本地仓库中mvn site安装站点二原创 2021-05-13 15:30:12 · 1004 阅读 · 1 评论 -
Nullable注解和函数式注册对象
一、@Nullable注解@Nullable 注解表示可以为空可以使用在方法上面,表示方法返回可以为空可以使用在属性上面,表示属性值可以为空可以使用在参数上面,表示参数值可以为空二、函数式注册对象 //函数式风格,创建对象,交给Spring进行管理 @Test public void testGenericApplicationContext(){ //1 创建 GenericApplicationContext 对象原创 2021-04-29 00:12:39 · 2570 阅读 · 0 评论 -
Spring5整合日志框架
Spring5框架自带了通用的日志封装,已经移除 Log4jConfigListener,官方建议使用 Log4j2。整合Log4j2日志框架首先引入jar包创建log4j2.xml配置文件<?xml version="1.0" encoding="UTF-8"?><!--日志级别以及优先级排序: OFF > FATAL > ERROR > WARN > INFO > DEBUG > TRACE > ALL --><!--原创 2021-04-28 22:14:11 · 315 阅读 · 0 评论 -
Spring中的事务
一、什么是事务事务是数据库操作最基本单元,逻辑上是一组操作,可能一个操作包括多条SQL语句,要么所有SQL语句都执行成功,如果有一个失败,所有的操作都要失败。二、事务四个特性(ACID)原子性一致性隔离性持久性三、Spring的事务管理事务的管理操作一般都是添加在Service层(业务逻辑层)在Spring进行事务管理操作有两种方式:编程式事务管理声明式事务管理声明式事务管理基于注解方式基于XML配置文件方式Spring进行声明式事务管理,底层...原创 2021-04-28 20:34:15 · 197 阅读 · 0 评论 -
JDBCTemplate的使用
一、什么是JDBCTemplateSpring 框架对JDBC进行了封装使用 JdbcTemplate 方便实现对数据库操作二、JDBCTemplate操作数据库——添加功能对应数据库创建实体类public class User { private String userId; private String userName; private String uStatus; public User() { } public User(Str原创 2021-04-27 02:06:37 · 446 阅读 · 0 评论 -
AOP面向切面编程
一、什么是AOP面向切面编程,是利用 AOP 可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。可以不通过修改源代码方式,在主干功能里面添加新功能。二、AOP底层实现原理AOP底层使用动态代理第一种:有接口的情况,使用 JDK 动态代理。创建接口实现类代理对象,增强类的方法。//创建接口,定义方法public interface UserDao { public int add(int a, int b);原创 2021-04-26 21:36:47 · 419 阅读 · 0 评论 -
基于注解方式实现Bean的管理
一、什么是注解注解是代码特殊标记,格式为@注解名称(属性名称=属性值, 属性名称=属性值..)。使用注解目的是为了简化 xml 配置。注解可以作用在类、方法、属性。二、创建对象的注解@Component@Service@Controller@Repository四个注解功能都是一样的,都是用来创建bean实例对象,但是@Controller一般用在Web层,@Service一般用在Service层,@Repository一般用在Dao层。三、基于注解方式实现对象创建引入依赖并开原创 2021-04-25 22:31:29 · 110 阅读 · 0 评论 -
基于XML配置文件方式实现Bean的管理
Bean的管理 = 创建对象(XML、注解) + 注入属性(构造器、set方法)一、基于XML方式创建对象 <!--配置User对象创建--> <bean id="User" class="spring5.User"></bean>使用bean标签可以实现对象的创建,其中id属性是唯一标识,class属性是类全路径。创建对象的时候,默认执行五参数构造方法。二、基于XML方式注入属性依赖注入(DI)通过DI来实现注入属性,需要在创建对象的基础.原创 2021-04-23 22:47:51 · 236 阅读 · 0 评论 -
Bean的作用域以及生命周期
一、Bean的作用域Spring默认情况下,创建的Bean都是单实例对象 @Test public void test1(){ //1.加载Spring配置文件 ApplicationContext context = new ClassPathXmlApplicationContext("userBean.xml"); //2.获取配置创建的对象 User user1 = context.getBean("User",原创 2021-04-23 21:27:20 · 331 阅读 · 0 评论 -
使用FactoryBean实现Bean的管理
Spring 有两种类型 bean,一种是我们自己定义的普通 bean,另外一种工厂 bean。普通的bean在配置文件中定义 bean 类型就是返回类型。FactoryBean在配置文件定义 bean 类型可以和返回类型不一样。第一步:创建类,让这个类作为工厂bean,实现接口FactoryBean第二步:实现接口里面的方法,在实现的方法中定义返回的 bean 类型public class MyFactoryBean implements FactoryBean<User>{原创 2021-04-23 20:23:43 · 111 阅读 · 0 评论 -
JSON在java中的使用
一、javaBean和json的互转JavaBean类public class Person { private Integer id; private String name; public Person() { } public Person(Integer id, String name) { this.id = id; this.name = name; } public Integer getId()原创 2021-04-17 23:11:02 · 553 阅读 · 1 评论 -
使用Filter和ThreadLocal组合管理事务
一、ThreadLocal的使用ThreadLocal的作用可以解决多线程的数据安全问题。ThreadLocal可以给当前线程关联一个数据,这个数据可以是普通变量、对象、数组、集合等。相当于Map一样存取数据,key为当前线程。每个ThreadLocal对象,只能为当前线程关联一个数据,如果要为当前线程关联多个数据,就需要使用多个ThreadLocal对象实例。每个ThreadLocal对象实例定义的时候,一般都是static类型。ThreadLocal中保存的数据,在线程先销毁后,会由JVM虚原创 2021-04-17 15:39:12 · 314 阅读 · 0 评论