本文主要是介绍记录一下自己见到过的八股面试题,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
八股面试题
长期更新
2023年12月16日
1、什么是反射?什么是代理?什么是静态代理与动态代理?什么是cglib反射?
2、hashCode到底有什么用?
hashCode是jdk根据对象的地址算出来的一个int数字,即对象的哈希码值,代表了该对象在内存中的存储位置。
我们都知道hashCode()方法是顶级类Object类的提供的一个方法,所有的类都可以进行对hashCode方法重写。
我们也知道在比较一个类是否相同时往往会重写equals方法,值得注意的是,重写equals方法的同时必须也要重写hashCode方法,多次调用一个对象的hashCode方法必须返回同一个数字,这也是必须遵守的规范,不然会造必须存在的危害。
3、什么是JIT?
4、GC原理及调优讲一下。
5、spring boot停机会做些什么呢,是什么流程呢?
什么是优雅停机:
就是对应用进程发送停止指令之后,执行的一系列保证应用正常关闭的操作。这些操作往往包括等待已有请求执行完成、关闭线程、关闭连接和释放资源等
就是对应用进程发送停止指令之后,能保证正在执行的业务操作不受影响,可以继续完成已有请求的处理,但是停止接受新请求
本质上是JVM即将关闭前执行的一些额外的处理代码
可以避免非正常关闭程序可能造成数据异常或丢失,应用异常等问题
优雅停机主要处理:
池化资源的释放:数据库连接池,HTTP 连接池,线程池
在处理线程的释放:已经被连接的HTTP请求
mq消费者的处理:正在处理的消息
隐形受影响的资源的处理:Zookeeper、Nacos实例下线等
未优雅停机:
当我们停止正在运行的应用程序或进程时,底层操作系统会向进程发送终止信号。在没有启用任何优雅关闭机制的情况下(如:kill -9),Spring Boot 应用程序将在收到信号后立即终止。
此时一些没有执行完的程序就会直接退出,可能导致业务逻辑执行失败,在一些业务场景下:会出现数据不一致的情况,事务逻辑不会回滚。
优雅停机使用场景:
一个基于springboot的服务,服务从网络接收请求,再把请求任务放入队列里交给线程池取异步消费请求任务。怎么样停止服务才能保证任务队列里的请求都处理完成了呢?
之前有了解过Java的ShutDown Hook机制,但是因为没有使用场景也没有深入学习,最近刚好又看到ShutDown Hook的一些东西,想着学习总结一下,做下学习记录。Java的Shutdown Hook是一种机制,允许开发者在Java虚拟机(JVM)即将关闭之前执行一些清理或终止操作。Shutdown Hook提供了一个钩子,允许开发者在JVM关闭时捕获到关闭事件并执行相应的逻辑。以下是一些使用场景:
- 资源释放和清理:当应用程序结束或JVM关闭时,可以使用Shutdown Hook来释放和清理打开的文件、网络连接、数据库连接等资源。这确保资源在程序终止之前得到适当的关闭,避免资源泄露和数据丢失。
- 日志记录和统计:Shutdown Hook可以用于记录应用程序的关键统计信息或生成最终的日志报告。通过在JVM关闭前执行这些操作,可以捕获应用程序在运行期间的关键数据,并生成相应的日志记录。
- 缓存刷新:如果应用程序使用了缓存机制,可以在JVM关闭前使用Shutdown Hook来刷新缓存,将缓存中的数据写回到持久化存储或其他目标中,确保数据的持久化和一致性。
- 任务终止和状态保存:在某些情况下,可能需要在应用程序终止时保存任务的当前状态,以便在下次启动时恢复。通过在Shutdown Hook中执行任务的状态保存操作,可以将任务的状态保存到持久化存储中,并在下次启动时进行恢复。
- 线程管理:Shutdown Hook还可以用于管理和终止应用程序中的线程。在JVM关闭前,可以使用Shutdown Hook发送终止信号给正在运行的线程,以确保它们在终止之前完成当前任务并进行清理操作。
6、什么是内存屏障?
7、什么是索引下堆?什么是二级索引?
8、什么是二级索引?
9、explain
10、什么是hreadlocal?什么是transmittedthreadlocal?
11、threadLocalMap、threadLocal、thread之间的联系和区别
这个问题的解答暂时
2023年12月24日
12、线程池是什么?什么是拒绝策略?线程池的用处主要有哪些?
线程池是Java代码中一组线程,使用了池化思想,减少了频繁创建线程和销毁线程所产生的cpu和时间损耗。
用处主要是:在cpu负载较小的情况下对同一组数据进行并行操作,或者将顺序操作分别新建一个线程去执行他们,另外就是是在一个同步线程的操作需要调用外部信息,则需要等待调用其他项目外的API,可以起一个异步线程去执行,防止因为调用其他接口等待时间过长报错,并且其实tomcat本身就是一个线程池,如果不太需要的情况下可以不使用。
mq的好处,1、对于mq或者新功能的扩展很方便2、可以不用将请求保存在内存中,可以让等待的请求容量大于部署的服务器的内存3、mq保存是独立的,不像用线程池,mq重启后请求还是可以回复的4、可以更好的检测消费情况,是否需要扩容5、跨语言支持,mq可以试试用任意一种语言编写的,如果是并发能力强的语言,可以帮助Java程序更好地执行项目
如果线程池使用的是现将请求放在数据库中,每次重启使用调度任务拿到后并且处理,也比单纯的使用线程池可靠性也强得多。
拒绝策略因该是有以下几种:
AbortPolicy:默认的策略,直接抛出RejectedExecutionException
DiscardPolicy:不处理,直接丢弃
DiscardOldestPolicy:将等待队列队首的任务丢弃,并执行当前任务
CallerRunsPolicy:由调用线程处理该任务
CPU 密集型任务(N+1): 这种任务消耗的主要是 CPU 资源,可以将线程数设置为 N(CPU 核心数)+1,多出来的一个线程是为了防止某些原因导致的线程阻塞(如IO操作,线程sleep,等待锁)而带来的影响。一旦某个线程被阻塞,释放了CPU资源,而在这种情况下多出来的一个线程就可以充分利用 CPU 的空闲时间。
I/O 密集型任务(2N): 系统的大部分时间都在处理 IO 操作,此时线程可能会被阻塞,释放CPU资源,这时就可以将 CPU 交出给其它线程使用。因此在 IO 密集型任务的应用中,可以多配置一些线程,具体的计算方法:最佳线程数 = CPU核心数 * (1/CPU利用率) = CPU核心数 * (1 + (IO耗时/CPU耗时)),一般可设置为2N。
13、说说强引用、软引用、弱引用、虚引用吧
14、跟我讲一下spring的设计模式吧,尤其是工厂模式/你对spring源码有了解吗,有看过那些?
15、什么是线程安全?
共享的内存安全问题,对于同时进行操作的过程中,反正是可以使用cas进行解决
16、解释一下什么是select、poll、epoll
用户程序进行IO操作实际依赖于linux系统内核read()、write()函数
read()函数的调用并不是直接从网卡把数据读取到用户内存中,而是把内核缓冲区中的数据复制到用户缓冲区中
write()函数的调用也并不是直接把数据写入网卡中,而是把用户缓冲区的数据写入到内核缓冲区中
网卡与内核缓冲区数据的读写则是由操作系统内核完成
17、保证mq的顺序性
需要保证生产和消费顺序性
生产者的:单一生产者、并且串行发送
对于消费者:投递顺序、有限重试、串行消费
18、volatile和synchronized的区别是什么?
volatile只能使用在变量上;而synchronized可以在类,变量,方法和代码块上。
volatile至保证可见性;synchronized保证原子性与可见性。
volatile禁用指令重排序;synchronized不会。
volatile不会造成阻塞;synchronized会。
19、ReentrantLock和synchronized区别
使用synchronized关键字实现同步,线程执行完同步代码块会自动释放锁,而ReentrantLock需要手动释放锁。
synchronized是非公平锁,ReentrantLock可以设置为公平锁。
ReentrantLock上等待获取锁的线程是可中断的,线程可以放弃等待锁。而synchonized会无限期等待下去。
ReentrantLock 可以设置超时获取锁。在指定的截止时间之前获取锁,如果截止时间到了还没有获取到锁,则返回。
20、守护线程是什么?
守护线程是运行在后台的一种特殊进程。它独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件。在 Java 中垃圾回收线程就是特殊的守护线程。
21、redis每个键可以使用多少内存
Redis的每个键可以使用最多 512MB 内存,而每个键值对最多可使用最大值为 1GB 内存(官方文档规定的数据大小要小于 1GB)。这样理解,单个键的键值最大长度可以有 512MB,即 512 * 1024 * 1024 bytes, 转化为十六进制应该是 0x80000 bytes。
22、List、Set、Sorted Set 他们最多能存放多少元素?
理论上 Redis 可以处理多达 232 的keys,并且在实际中进行了测试,每个实例至少存放了2亿5千万的 keys。我们正在测试一些较大的值。
任何 list、set 和 sorted set 都可以放 232 个元素。
换句话说,Redis 的存储极限是系统中的可用内存值。
理论上,一个 Redis 实例最多能存放约 2^32 个 keys,即大约 42亿个。但实际上,最大的限制因素取决于服务器的物理内存大小和操作系统的限制。在实际使用中,需要根据机器的配置和使用场景进行调整和优化。
23、redis的内存淘汰策略是什么?
24、AOP的失效情况是那些?
spring的AOP是基于动态代理生效的
同一个类中方法调用;内部类方法调用;私有方法无法调用;static修饰方法;final修饰的方法,无法被重写。
25、应用数据往哪存?
26、什么是JMM?
27、类、类对象、实例对象
28、Feign和OpenFeign
29、spring是怎么管理事务的,spring的事务传播机制是什么?
spring的事务也遵从ACID
30、什么是响应式编程
31、简述一下常用的负载均衡策略
32、什么是MDC,它有什么作用?
33、什么是分布式锁?怎么实现?
可以使用redis或者zookeeper实现,首先要考虑的是要新增一套系统的话是否需要多消耗一部分钱,多消耗一部分精力去维护,如果有redis最好还是先用redis吧。一般为了保证redis分布式锁的构建过程中不出错,尽量使用框架,如redisson。期间会存在一个锁续期的问题。并且如果有redis集群,需要从主从、哨兵等角度看问题,这下就引入了redlock,用来进行主从之间的传递数据,共享完成后再把锁给请求。还会有解锁解成别人的所的问题,通过加uuid来解决这个问题。redis也是遵从AP理论,不满足c条件,
34、Java有多少种锁?各有什么作用?
35、有了解过ReentrantReadWriteLock吗?
36、分段锁算是面试中经常会被问到,希望各位记住。
JAVA里面主要有ReentrantLock ,synchronized,Lock三种,类别也是不一样
synchronized:属于独占锁、悲观锁、可重入锁、非公平锁
ReentrantLock:继承了Lock类,可重入锁、悲观锁、独占锁、互斥锁、同步锁。
Lock:Java中的接口,可重入锁、悲观锁、独占锁、互斥锁、同步锁
37、 Redis 内存淘汰策略
38、怎么在不使用所的情况下保证线程安全?
尽量脱离共享变量的影响,减少共享变量的使用。使用cas来解决
40、MVCC和LBCC的逻辑给说一下?MySQL隔离机制是什么?怎么做到的?undolog和binlog有什么用?
41、redis LRU驱动事件(LRU eviction)是什么?
42、订阅者模式是什么?
43、百万级的数据怎么做到导入导出?
44、nacos配置中心你了解吗?
45、哈希攻击是什么?
有时候攻击方如果知道了哈希策略,就会生成最后哈希值一样的字符串持续攻击哈希桶,导致性能从O(1)下降到on,解决方法,Java8通过将哈希链表超过八个的转化为红黑树,是的性能最多只是下降到O(logn),可以接受,redis可以通过rehash使得数据分布更均匀。
问题一:HashMap为什么要加入红黑树
当有大量hashCode相同的数据插入时,会使得哈希表中某一个桶下面的链表过长。这时对该桶下面进行任何操作时间复杂度都是O(N)级别的。
jdk1.8在桶中链表过长时,会将其转化为红黑树,红黑树的任何操作都是O(logN)级别。这样即使有大量hashCode相同的数据,HashMap在该桶下操作的时间复杂度也只会从O(1)降到O(logN),而不会降到O(N)。
问题二:为什么不用TreeMap代替HashMap。
HashMap的使用场景大多为存数据,取数据,查数据。
TreeMap的使用场景大多为将存储的数据有序输出。
1.在哈希冲突少的情况下,存数据,取数据,查数据。HashMap时间复杂度均为O(1),而TreeMap在这3个操作中,时间复杂度均为O(logN)。
2.即使存在大量哈希冲突,hashMap中,也只在某一个桶中的操作复杂度为O(N),在其他桶中操作复杂度依然为O(1)。使用TreeMap是所有操作为O(logN)。
3.大量哈希冲突又是一件极难发生的事情(一般只存在于恶意攻击中),所以在大多数情况下HashMap都没有必要使用红黑树。
前两个点讲述TreeMap替换不了HashMap的原因,第3点讲述HashMap没有一上来就树化的原因。
问题三:重写HashCode和equals对HasaMap的影响。
HashMap是通过实例对象的hashCode方法去找数据所在的桶,再通过对象的equal去该桶中寻找对应的数据。去比较对象是否相等。
当我们new了两个相同数据的对象,不重写hashCode和equals。插入到hashMap中时,由于hashCode和equals均不相等。hashMap会认为这是两个不同的对象。
重写HasaCode和equals则会认为这两个对象是相同的。
2023年12月30日
46、说说seata的实现原理
47、怎么保证分布式系统的幂等性,在高并发的情况下?
一般在用户超时重试、mq重复消费、rpc超时重传机制、外部应用恶意重复请求的情况下会出现。
1、使用分布式系统的uuid替代MySQL的自增id,使用唯一主键方式实现幂等,但是逻辑在数据库,尽量还是不要这么做
2、乐观锁实现幂等,通过版本号实现
3、使用分布式锁
4、获取token
48、大厂是如何做权限控制的?除了RBAC和IAM,数据权限反而更重要 !
49、Nacos 是如何同时实现AP与CP的
50、sql查询速度的影响要素
51、BeanPostProcessor
52、in与exist的区别
53、什么是逃逸分析
54、Redis为什么使用C语言中的字符串?要用通过SDS来实现呢?
55、Java中的对象一定是在堆上分配的吗?
56、什么是索引下推?它的使用条件是什么?
57、@Import注解在实际开发中的使用
@import 往往和@enable***结合使用,可以设置include***importselector,扫描Metainfo下的路径,去加载对应的bean。
一般都是给框架的start用的。因为大部分的框架都不依赖spring,而要做一个spring boot的starter,就需要把你之前的底层框架的对象交给spring管理。包括一些额外的功能,还可以结合自定义enable注解。
还有楼上说的那个那第三方的类确实是通过Maven引进来的。但是没有spring的话,很多的对象都是类new出来的。尤其是对于web开发,每个线程都要new,很多成员变量会导致一直gc。有了spring以后new一个作为springbean就可以了。可以避免重复的创建对象。这也是为什么很多框架都要兼容spring的原因。但因为早期设计的原因是xml,被很多人唾弃为配置地域。其实以springsecurity最让人头大。后来才有了springboot。最开始这个注解就是被用作以第三方的类去new一个bean。后来springboot出来以后,就被当做enable注解和框架的start了。哦对了,这里得区分一下类和对象的区别。大部分的对象都是类new【小部分除外,有些和反射相关的特殊的】
58、Countdownlatch执行任务+Future
59、线程等待的四种方式-join/future/countDownLatch/cylicBarrier实现
60、单例模式为什么使用volatile,以及双重检查
61、[ReentrantLock与synchronized的区别]
1、与synchronized相比,ReentrantLock提供了更多,更加全面的功能,具备更
强的扩展性。例如:时间锁等候,可中断锁等候,锁投票。
2**、ReentrantLock还提供了条件Condition**,对线程的等待、唤醒操作更加详细和
灵活,所以在多个条件变量和高度竞争锁的地方,ReentrantLock更加适合(以后
会阐述Condition)。
3、ReentrantLock提供了可轮询的锁请求。它会尝试着去获取锁,如果成功则继
续,否则可以等到下次运行时处理,而synchronized则一旦进入锁请求要么成功要
么阻塞,所以相比synchronized而言,ReentrantLock会不容易产生死锁些。
4、ReentrantLock支持更加灵活的同步代码块,但是使用synchronized时,只能
在同一个synchronized块结构中获取和释放。注:ReentrantLock的锁释放一定要
在finally中处理,否则可能会产生严重的后果。
5、ReentrantLock支持中断处理,且性能较synchronized会好些。
62、wait和notify 为什么要在synchronized代码块中
因为在synchronized代码块中对共享变量的访问是OK的,我们则需要对其他线程进行阻塞,即调用wait方法产生的结果,在对共享变量操作完成之后,则需要使用notify方法对其他线程进行唤醒。
63、请简单说一下你对受检异常和非受检异常的理解
什么是受检异常和非受检异常
可以从三个方面回答这个问题一、首先是异常的本质)
一、首先是异常的本质
受检异常和非受检异常,都是继承自 Throwable 这个类中,分别是 Error 和
Exception,Error 是程序报错,系统收到无法处理的错误消息,它和程序本身无关。
Excetpion 是指程序运行时抛出需要处理的异常信息如果不主动捕获,则会被
jvm 处理。
二、然后是对受检异常和非受检异常的定义
前面说过受检异常和非受检异常均派生自 Exception 这个类。
\1. 受检异常的定义是程序在编译阶段必须要主动捕获的异常,遇到该异常有两种处理方法
通过 try/catch 捕获该异常或者通过 throw 把异常抛出去
\2. 非受检异常的定义是程序不需要主动捕获该异常,一般发生在程序运行期间, 比如 NullPointException
三、最后我还可以说下他们优点和缺点) 受检异常优点有两个:
第一,它可以响应一个明确的错误机制,这些错误在写代码的时候可以随时捕获并且能很好的提高代码的健壮性。
第二,在一些连接操作中,它能很好的提醒我们关注异常信息,并做好预防工作。
不过受检异常的缺点是:抛出受检异常的时候需要上声明,而这个做法会直接破坏 方 法 签 名 导 致 版 本 不 兼 容 。 这 个 恶 心 特 性 导 致 我 会 经 常 使 用
RuntimeException 包装。
非受检异常的好处是可以去掉一些不需要的异常处理代码,而不好之处是开发人员可能忽略某些应该处理的异常,导致带来一些隐藏很深的 Bug,比如流忘记关闭?连接忘记释放等
————————————————
版权声明:本文为CSDN博主「皮皮攻城狮」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_44797327/article/details/135280015
64、为什么JDK9要将,String的底层实现由char[]改成byte[]?
在 JDK 9 中,Java 语言的 String 类将底层实现从 char[] 数组改为 byte[] 数组,这是因为 JDK 9 引入了 Compact Strings 机制。
Compact Strings 通过改变强制性编码和使用更有效的内存表示来优化 String 对象的内存使用。在 JDK 8 及之前的版本中,String 对象的底层表示采用 UTF-16 编码,并使用 char 数组存储,这有助于支持字符串的快速随机访问,但是对于大多数字符串来说,它们的大部分字符使用的都是1个字节的 ASCII 字符,因此使用 char 存储这些字符存在内存浪费的问题。
65、为什么springboot达成的jar包可以直接运行
66、什么是JMM(Java内存模型)?
这篇关于记录一下自己见到过的八股面试题的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!