面试汇总
文章平均质量分 90
煎丶包
这个作者很懒,什么都没留下…
展开
-
ThreadLocal从变量副本的角度解决多线程并发安全问题
ThreadLocal从变量副本的角度解决多线程并发安全问题之前我们讲的高并发场景下的线程安全问题,可以使用Synchronized同步关键字、Lock手动加锁的方式去解决,什么轻量级锁、偏向锁、重量级锁、可重入锁等等,实际上本质都是控制线程,使得多个线程同步的去访问共享资源。之所以多线程存在线程安全问题,就是因为多个线程访问同一个共享资源导致的,多个线程之间属于竞争关系,很容易就会导致数据的不安全。我们说了加锁实际上保证了各个线程之间同步、有序的去访问共享资源,难道不加锁就没有办法解决多线程安全问题原创 2021-10-03 18:56:39 · 780 阅读 · 0 评论 -
【源码】走一遍源码弄清ArrayList容器的扩容机制
【源码】走一遍源码弄清ArrayList容器的扩容机制首先我们来看看ArraysList容器在整个Java集合框架中所处的位置由此可见ArrayList是Java集合框架中,两大派系中Collection接口的子接口List的实现类我们从源码入手可以看到ArrayList底层数据结构实际上是一个**Object类型的数组**,由于Object是所有类的父类,所以ArrayList集合可以存放任意类型的元素,并且存放的元素是有序的、可重复的、可随机访问的。接下来我们就以add()方法为突破口,来解原创 2021-10-01 16:00:23 · 482 阅读 · 0 评论 -
【源码】看一看Spring如何使用三级缓存解决循环依赖问题
【源码】看一看Spring如何使用三级缓存解决循环依赖问题我们之前文章讲Bean的创建过程中,提到了如果当前bean依赖的其它bean,就会调用getBean()方法把依赖的bean先创建出来可是你有没有想过,如果当前Bean依赖于另一个Bean,而另一个Bean又就形成了依赖于当前Bean,或者当前Bean依赖于自己,这样依赖关系形成了一个闭环。这就是我们这篇文章将要说的Bean的循环依赖问题!首先我们要明确Spring不是能够解决所有情况下的循环依赖问题的,只能解决:出现循环依赖的Bean原创 2021-09-28 22:18:19 · 618 阅读 · 0 评论 -
从Spring容器刷新过程中的创建Bean阶段来说说Bean的生命周期
从Spring容器刷新过程中的创建Bean阶段来说说Bean的生命周期我们所说的Bean的生命周期指的是从Bean的创建、初始化、使用Bean、销毁的整个过程。而IOC容器就是负责管理Bean的整个生命周期。实际上Bean的生命周期在容器启动的时候就已经开始了,严格来说,你可以认为容器启动时,从注解配置读取器读取标有注解的类,转换为BeanDefinition对象时,Bean的生命周期就已经开始了。打个比方,小宝宝的生命的起点,并不是说从出生落地开始算的,而是从妈妈肚子里面,基本上可以算是生命已经开始了。原创 2021-09-28 02:56:04 · 466 阅读 · 0 评论 -
【源码】走一遍refresh()方法的源码就能弄懂Spring容器的创建过程
【源码】走一遍refresh()方法的源码就能弄懂Spring容器的创建过程Spring框架的两大核心思想,一个是IOC控制反转,另一个就是AOP面向切面编程。而IOC控制反转指的是将创建对象的操作交给Spring容器来解决,容器同一对所有的对象进行管理,我们无需关心创建对象时,对象之间的依赖关系,只需要在使用对象时从容器中获取即可。要想从容器中获取对象来使用,那就必须首先创建出这个Spring容器,这篇文章就来从源码角度出发,来看看Spring容器的创建过程。创建Bean可以使用XML配置文件,也可以原创 2021-09-27 13:17:43 · 314 阅读 · 0 评论 -
Redis还可以干分布式锁的活儿
Redis还可以干分布式锁的活儿现在的业务开发一般都是分布式微服务,多个微服务之间要保证同一时刻,同一用户只能有一个请求被处理,为了防止关键业务出现数据冲突和并发错误。在只有一台服务器,单机的情况下,为了防止出现并发问题,你也许想到可以使用Synchronized同步关键字或者使用Lock手动加锁来防止高并发的线程安全问题,但是如果在分布式集群的情况下,多台服务器协同工作,再使用Synchronized同步关键字和Lock锁还能起作用吗?当然不能了,单机锁只能管控住自己这一台服务器,多台服务器之间,物理原创 2021-09-26 03:37:47 · 140 阅读 · 0 评论 -
讲一讲Redis Cluster分布式集群是如何保证可扩展的
讲一讲Redis Cluster分布式集群是如何保证可扩展的之前的文章我们讲了Redis的主从架构模式、Sentinel哨兵模式,这篇文章我们再来讲讲Redis Cluster分布式集群模式。不要搞混主从模式、Sentinel模式、Cluster集群模式,这三者的侧重点或者说作用是不相同的。主从架构模式主从模式主要实现数据备份、容灾恢复,以及通过主从复制实现读写分离,通常是一主多从的架构模式,主服务器用来写,从服务器用来读。主从架构模式侧重于支持高并发。Sentinel哨兵模式多个Sent原创 2021-09-25 22:48:23 · 292 阅读 · 0 评论 -
说一说Redis的Sentinel模式是如何保证服务器高可用的
说一说Redis的Sentinel模式是如何保证服务器高可用的我们之前文章说的Redis的主从架构模式实现了读写分离,支持了高并发的业务场景。主从模式也由单台Redis服务器变成了多台Redis服务器,服务器数量一多,当某服务器发生故障宕机的时候,可能就会影响到其它正在工作的服务器,然后产生连锁反应,进而使得整个系统崩溃。对于这种情况我们需要拿出一个方案,使得在某一台或者多台服务器宕机时,要保证不会影响到其它正常工作的服务器,继续维持整个系统正常运转。而Redis的哨兵模式就提供了高可用的解决方案!哨兵原创 2021-09-24 23:36:14 · 199 阅读 · 2 评论 -
从Redis主从架构模式角度说一说是如何支持高并发的
从Redis主从架构模式角度说一说是如何支持高并发的我们说Redis是基于内存操作的数据库,追求的是简单高效,实现了高性能的数据访问。单机Redis所能支持的QPS一般都在几万左右,一般不会超过10w+,但是,在有些实际业务中,像是秒杀、双十一,这些业务场景的QPS很有可能达到惊人的数字!所以说高并发场景下的单机Redis显得就有些吃力了,不用怕,Redis官方早就想到了高并发的场景,我们可以使用多个Redis实例,搭建主从架构模式来支撑高并发的场景。主从架构模式,也就说有一台Redis服务器做主机,多原创 2021-09-24 15:11:41 · 250 阅读 · 0 评论 -
Redis缓存常见问题——穿透、击穿、雪崩
Redis缓存常见问题——穿透、击穿、雪崩Redis最常用来做缓存,它是基于内存来操作数据的,当数据量过大时难免会遇到一些缓存问题。这篇文章就来说一说Redis常见的缓存问题。缓存穿透我们说当发送请求来查询某个数据时,首先会从Redis缓存中查询,如果缓存中有就直接返回,如果没有请求才会到数据库中查询。而缓存穿透指的就是当访问一个redis缓存和数据库都不存在的key时,此时这个请求就会直接到数据库中查询,但是数据库中也查不到任何数据,而且也没有办法写缓存。这样情况缓存相当于没起作用,当请求量过大时,原创 2021-09-23 14:45:17 · 445 阅读 · 1 评论 -
说一说Redis事务是否满足ACID以及WATCH监视命令的作用
说一说Redis事务是否满足ACID以及WATCH监视命令的作用MySQL关系型数据库InnoDB存储引擎支持事务,Redis这个非关系型数据库也同样实现了事务功能。Redis 可以通过 MULTI,EXEC,DISCARD 和 WATCH 等命令来实现事务(transaction)功能。MULTI命令表示开始事务,之后可以输入多个命令,此时Redis并不会执行这些命令,而是将这些命令入队,当输入EXEC命令时表示执行事务,Redis会从队列中挨个取出命令来执行,执行完所有命令之后统一返回结果。DI原创 2021-09-23 02:44:45 · 322 阅读 · 0 评论 -
从内存淘汰策略和过期键删除来聊一聊Redis内存管理机制
从内存淘汰策略和过期键删除来聊一聊Redis内存管理机制我们说过Redis是基于内存操作的数据库,所有的数据保存在内存中,所以读写速度非常的快。既然数据都存放在内存中,内存毕竟有限,远远比不上磁盘的存储空间,所以如果不及时清理掉一部分没有用的数据,就会导致内存不足。这篇文章就来聊一聊Redis内存淘汰策略和过期键的删除。Redis是可以在redis.conf这个配置文件中设置最大占用内存的,如果不设置最大内存大小或者设置最大内存大小为0,在64位操作系统下不限制内存大小,在32位操作系统下最多使用3GB原创 2021-09-22 14:49:34 · 196 阅读 · 0 评论 -
谈一谈Redis持久化这个容灾恢复机制
谈一谈Redis持久化这个容灾恢复机制服务器“闹情绪”宕机可以说是非常常见的情况了,要想“哄好”服务器,Redis是如何保证服务器挂掉重启之后,能够恢复数据的呢?这就是本篇文章要讲的Redis持久化机制。所谓的持久化就是将内存中的数据写入到磁盘当中去,这样一旦服务器发生故障宕机,重启服务器之后可以从磁盘中读取之前的数据来恢复数据。Redis不同于Memcached的很重要一点就是Redis 支持持久化,而且支持两种不同的持久化操作,RDB方式和AOF方式。谁敢说我家的服务器绝对不会宕机?所以持久化机制对原创 2021-09-21 16:28:29 · 359 阅读 · 0 评论 -
从处理请求的核心流程谈一谈Redis到底是单线程还是多线程
从处理请求的核心流程谈一谈Redis到底是单线程还是多线程随着Redis版本的不断更新,Redis在处理请求方面也在不断的优化,由单线程的概念逐渐引入了多线程的概念。那么Redis到底是单线程还是多线程呢?在Redis 4.0版本之前,Redis完全是单线程,没有引入多线程这个概念。因为Redis是完全是基于内存操作的,通常情况下CPU不会是redis的瓶颈,于是就采用单线程模型处理请求,如果使用多线程的话,反而会变得更复杂,同时还涉及到了多线程的上下文切换,带来了额外的性能消耗。所以,Redis读写速原创 2021-09-21 10:15:28 · 452 阅读 · 0 评论 -
从Redis底层的数据结构来说说为什么读写数据这么快
从Redis底层的数据结构来说说为什么读写数据这么快Redis是一个C语言编写的非关系型数据库,与MySQL关系型数据库不同的是,Redis的数据是存储在内存中的,所以说使用Redis读写数据非常的快!因此Redis常用来的做缓存。当然,之所以Redis读写数据这么快,出了它的数据存储在内存中这个原因以外,还与它的底层数据结构有关!这篇文章就从Redis底层数据结构来分析为什么读写数据这么快。String类型可以说我们平常操作最多的数据类型就是字符串了,对于String类型我们最常用的命令就是set和原创 2021-09-20 17:34:35 · 762 阅读 · 3 评论 -
说一说JVM类加载子系统使用的各种类加载器
说一说JVM类加载子系统使用的各种类加载器之前我们在《从JVM层面谈一谈类的加载过程》这篇文章中,详细的介绍了类加载的过程。我们说一个类,从class字节码二进制数据流转化为类模板加载到系统内存中,这一过程是由类加载子系统实现的,确切的说是由类加载子系统中的各种类加载器实现的。这篇文章就来谈一谈都有哪些类加载器以及它们的作用都是什么。所有的类都是由ClassLoader进行加载的,Classloader负责通过各种方式将类信息的二进制数据流读入到JVM内部的方法区,形成一个类模板数据结构,进而转换为一个原创 2021-09-18 21:55:33 · 350 阅读 · 0 评论 -
从JVM层面谈一谈类的加载过程
从JVM层面谈一谈类的加载过程之前在Java内存区域详解(万字总结!一篇入魂!点赞收藏!)这篇文章中详细讲解了Java内存区域,我们下面再放一张图,回顾一下Java内存区域都划分为了哪几部分通过JVM整体架构来看,Java内存区域,也就是运行时数据区,是JVM的核心。我们知道Java内存区域是用来存放程序运行过程中产生的数据的区域,如果我们要向将Java程序运行起来,首先必须把编译出来class文件加载到内存中,而负责加载的就是JVM中的类加载子系统,它负责将编译好的class文件加载到内存中。这篇文原创 2021-09-17 17:24:55 · 148 阅读 · 0 评论 -
从ThreadPoolExecutor源码着手来谈一谈并发中使用的线程池
从ThreadPoolExecutor源码着手来谈一谈并发中使用的线程池线程池,关键在于一个**“池”字,你可以联想一下数据库连接池、字符串常量池等等,都是实际上都是利用池化技术**来减少每次获取资源的消耗,提高对资源的利用率。在高并发多线程的场景下,某个时间段内肯定不只有一个线程在工作,而是有大量的线程同时在执行任务。当面对大量的请求等待处理时,我们不可能一个一个的创建出线程,然后分配请求任务让这个线程去处理,这样效率也太低了。怎么解决呢?我们想如果说事先创建好了很多线程,随时待命,一旦有请求发送过来,原创 2021-09-16 17:22:25 · 181 阅读 · 0 评论 -
从Java内存模型的角度来解读volatile关键字
从Java内存模型的角度来解读volatile关键字在之前关于高并发线程同步控制的文章中,我们讲了Synchronized关键字的作用以及底层JVM的实现原理,也讲了另一把ReentrantLock可重入锁的作用及底层源码的实现。而为了保证多线程情况下线程之间的同步,除了加锁以外,还可以使用volatile关键字,它是JVM提供的一个轻量级的同步机制。首先我们要明确并发编程的3个重要特性:原子性一次操作或者多次操作,要么所有的操作全部都执行并且不会受到任何外界因素的干扰而中断,要么就全部都不执行原创 2021-09-14 20:26:50 · 159 阅读 · 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 · 3721 阅读 · 0 评论 -
结合JVM深入谈一谈Synchronized关键字的神奇之处
结合JVM深入谈一谈Synchronized关键字的神奇之处今天就来聊一聊Synchronized这个关键字。一提到Synchronized这个关键字,可能你马上联想到同步、加锁、多线程并发等等这些词语,仿佛感觉Synchronized关键字出镜率很高,感觉哪里都有它的身影。其实,Synchronized在很早的JDK版本中就已经存在了,可以说是元老级别的存在,主要解决的是多线程之间同步的访问资源,被Synchronized关键字修饰的方法或者代码块在任意时刻只能有一个线程执行。在早期的JDK版本中,S原创 2021-09-11 19:49:35 · 161 阅读 · 0 评论 -
Java垃圾回收机制详解(万字总结!一篇入魂!)
Java垃圾回收机制详解之前在《Java内存区域详解》这篇文章中,详细介绍了JVM内存区域的划分,以及创建对象时内存的分配情况。Java的自动内存管理机制,除了自动申请内存还会自动释放内存,这篇文章就来说一说Java内存回收机制。首先我们要明确几点,问什么要回收内存?哪些内存是需要回收的?什么时候回收?应该怎样回收?(Why?What?When?How?)举个例子,垃圾桶,你平时制造出来的垃圾都随手扔到了垃圾桶里,这垃圾桶就好比堆空间,你扔进去一个垃圾,就好比在堆空间自动申请的一块内存来存放这个垃圾,原创 2021-09-08 10:56:33 · 2350 阅读 · 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 · 223 阅读 · 0 评论 -
Java内存区域详解(万字总结!一篇入魂!点赞收藏!)
Java内存区域详解JVM自动内存管理机制,可以使得不像C/C++语言那样,需要手动的申请和释放内存,Java将内存的申请和释放完全交给JVM来管理,所以并不容易出现内存泄漏和内存溢出的问题。但是并不代表不会发生,所以我们必须要熟悉JVM,要熟悉JVM自动内存管理的机制,这样我们在发生内存问题时,才知道该如何下手去解决。JVM在运行时会把管理的内存划分为不同的数据区域,包括线程共享的堆、方法区,以及线程私有的虚拟机栈、本地方法栈、程序计数器。一共五大部分。但是在JDK 8前后,内存区域的划分出现了变动,原创 2021-09-04 15:27:44 · 965 阅读 · 0 评论 -
JMM详解与volatile关键字
一、Java内存模型——JMMJMM本身是一种抽象的概念,并不真实存在,它描述的是一组规则或者规范,就想JVM一样通过JMM规范定义了程序中各个变量(包括实例字段、静态字段和构成数组对象的元素)的访问方式JMM的可见性、原子性、有序性使得线程安全得到保证其中JMM对同步做出了规定:线程加锁前,必须读取主内存的最新值到自己的工作内存线程解锁前,必须把共享变量的值刷新回主内存加锁解锁必须是同一把锁由于JVM运行程序的实体是线程,而每个线程创建时JVM都会为其创建一个工作内存,工作内存是每个线原创 2021-08-10 15:45:53 · 155 阅读 · 0 评论 -
字符串方法intern()详解
一、intern()方法运行时常量池是方法区的一部分,在JDK 8的时候,方法区概念的落地实现由永久代变成了元空间intern()方法的源代码如下图所示intern()方法是一个本地方法调用该方法时,如果字符串常量池中已经存在一个等于此String对象的字符串,就直接从常量池中返回这个字符串对象的引用如果调用该方法的这个字符串对象,目前字符串常量池中还并不存在这个字符串对象,也就是说这个字符串对象是首次出现的,那么就新建并添加这个字符串对象到字符串常量池中,并返回新建的字符串对象的引用二、原创 2021-08-09 10:59:47 · 7755 阅读 · 3 评论