java面试题实战

一.linux

用过那些常用的命令:pwd,ls,cd,mkdir等

如何打开一个文件:cat、more命令

打开一个文件,搜索显示内容: cat hrun.log | grep "关键字"

打包与压缩命令是什么?tar -cvf  xxx,gzip  xxx

**根据关键字查看前后10行日志,并显示行号 :cat -n hrun.log | grep "关键字"-C 10

一个文件权限为754 代表什么含义 :1、第一位7,文件所有者拥有的权限为可读(4)可写(2)可执行(1)
2、第二位5,文件所有者同组用户的权限为可读(4)不可写(0)可执行(1)
3、第三位4,代表公共用户的权限为可读(4)不可写(0)不可执行(0)

1.查看文件系统大小命令 df -m

2.查询线程与杀死线程命令:ps -ef|grep kill -9 线程号 

3.怎样查询java进程的端口号

使用netstat命令netstat -tulnp | grep java;使用jps命令jps -lV

二.java

1.JAVA面向对象编程重要的特性:封装,继承,多态和抽象

2.接口和抽象类的区别是什么:类可以实现很多个接口,但是只能继承一个抽象类
类如果要实现一个接口,它必须要实现接口声明的所有方法。但是,类可以不实现抽象类声明的所有方法,当然,在这种情况下,类也必须得声明成是抽象的。

3.arraylist 和 LinkedList区别:ArrayList是基于线性数组的存储结构,自动扩容至原来1.5倍,可动态指定,适合快速访问(get/set)
LinkedList是基于双向链表的存储结构,无容量限制,适合添加和删除(add/delete),不适合快速访问

4.final、finally、finalize的区别:final:java关键字,修饰类、不能被继承,修饰变量或方法,不能修改或重写
finally:异常处理的一部分,只能在try/catch语句中使用,表示finally中的代码一定会执行
finalize:Object中的方法名称,在GC启动且对象将要被回收时由系统调用,不需要程序员手动调用
5.Java集合类有那些:Set,List,MAP,Collection

6.Java虚拟机内存模型的五大区域:

程序计数器:指示当前线程所执行的字节码指令的行号指针。

虚拟机栈:存放局部变量表、操作数栈、动态链接和方法出口等信息。

本地方法栈:为虚拟机使用的Native方法服务。

堆:存放对象实例,是垃圾收集器管理的主要区域。

方法区:存放已被加载的类信息、常量、静态变量、编译后的代码等数据

7.spring中用到的设计模式,spring bean默认单例,单例的好处:

单例bean的优势
由于不会每次都新创建新对象所以有一下几个性能上的优势。
1、减少了新生成实例的消耗
新生成实例消耗包括两方面,第一,spring会通过反射或者cglib来生成bean实例这都是耗性能的操作,其次给对象分配内存也会涉及复杂算法。
2、减少jvm垃圾回收
由于不会给每个请求都新生成bean实例,所以自然回收的对象少了。
3、可以快速获取到bean
因为单例的获取bean操作除了第一次生成之外其余的都是从缓存里获取的所以很快。

单例bean的劣势
单例的bean一个很大的劣势就是他不能做到线程安全!由于所有请求都共享一个bean实例,所以这个bean要是有状态的一个bean的话可能在并发场景下出现问题,而原型的bean则不会有这样问题(但也有例外,比如他被单例bean依赖),因为给每个请求都新创建实例。

8.spring的IOC和AOP理解,spring的好处,依赖注入的方式有哪些:IOC:控制反转,把对象的创建权利交给spring,实现方式DI
AOP:面向切面编程,重复的功能抽取出来,动态切入到需要的方法中,减少重复代码,降低耦合度
注入方式:构造方法注入、setter方法注入、接口注入、注解注入                  

9.在项目中怎样统一捕获异常,封装成错误码:使用@ControllerAdvice和@ExceptionHandler注解来创建全局异常处理器。

10.Spring框架中的事务处理有几种:请分别阐述两者的区别:spring提供的事务管理可以分为两类:编程式的和声明式的。编程式的,比较灵活,但是代码量大,存在重复的代码比较多;声明式的比编程式的更灵活.

11.Mybatis如何执行批量插入:insert into Author (username, password, email, bio) values
  <foreach item="item" collection="list" separator=",">
    (#{item.username}, #{item.password}, #{item.email}, #{item.bio})
  </foreach>

12.Springcloud的核心组件有哪些1.Eureka/Nacos注册中心2.Ribbon负载均衡3.Hystrix/Sentinel4.Fegin/Dubbo5.Zuul/Gateway网关

13Eureka 和 ZooKeeper的区别:Eureka取CAP的AP,注重可用性,Zookeeper取CAP的CP重一致性。(2)Zookeeper在选举期间注册服务瘫痪,虽然服务最终会恢复,但选举期间不可用。(3)eureka的自我保护机制,会导致一个结果就是不会再从注册列表移除因长时间没收到心跳而过期的服务。依然能接受新服务的注册和查询请求,但不会被同步到其他节点。不会服务瘫痪。
(4)Zookeeper有Leader和Follower角色,Eureka各个节点平等。
(5)Zookeeper采用过半数存活原则, ureka采用自我保护机制解决分区 。
(6)eureka本质是一个工程,Zookeeper只是一个进程。

14.防重复消息幂等性解决方案(服务的消费,如何避免重复消费):消息中加唯一标识,业务逻辑判断,redis分布式锁、zookeeper分布式锁、数据库唯一性

15.服务熔断和服务的降级的区别:服务降级
由于爆炸性的流量冲击,对一些服务进行有策略的放弃,以此缓解系统压力,保证目前主要业务的正常运行。它主要是针对非正常情况下的应急服务措施:当此时一些业务服务无法执行时,给出一个统一的返回结果。
服务熔断
由于爆炸性的流量冲击,对一些服务进行有策略的放弃,以此缓解系统压力,保证目前主要业务的正常运行。它主要是针对非正常情况下的应急服务措施:当此时一些业务服务无法执行时,给出一个统一的返回结果。

16.什么是缓存穿透、缓存击穿、缓存雪崩和预防方案

1.什么是缓存穿透
 • 正常情况下,我们去查询数据都是存在。那么请求去查询一条压根儿数据库中根本就不存在的数据,也就是缓存和数据库都查询不到这条数据,但是请求每次都会打到数据库上面去。这种查询不存在数据的现象我们称为缓存穿透。
 • 解决办法:1.缓存空值。2.BloomFilter(布隆过滤)。

2.什么是缓存击穿?
key可能会在某些时间点被超高并发地访问,是一种非常“热点”的数据。这个时候,需要考虑一个问题:缓存被“击穿”的问题。
当这个key在失效的瞬间,redis查询失败,持续的大并发就穿破缓存,直接请求数据库,就像在一个屏障上凿开了一个洞。
 • 解决方案: 1.使用互斥锁(mutex key)。2.逻辑过期。

3.缓存雪崩,是指在某一个时间段,缓存集中过期失效。对这批数据的访问查询,都落到了数据库上,对于数据库而言,就会产生周期性的压力波峰。
解决方案:
 • 数据分类分批处理:采取不同分类数据,缓存不同周期
 • 相同分类数据:采用固定时长加随机数方式设置缓存
 • 热点数据缓存时间长一些,冷门数据缓存时间短一些
 • 避免redis节点宕机引起雪崩,搭建主从集群,保证高可用

17.为什么用redis:redis 的优势比较多,如高性能,高可用,丰富的数据类型、原子性、扩展性比较强、可持久化、生态完善等等,但是比较有决定性的还是高性能和丰富的数据类型支持(string、list、set、sortedset(有序集合)、hash等)

18.redis常用命令String:SET key value、GET key、DEL key,SETEX key seconds value、SETNX key value
hash<HashMap>:HSET key field value ...field value,HGET key field,HDEL key field ...field,
list<List>:LPUSH/RPUSH key value1 [value2],LINDEX key index,LRANGE key start stop,LLEN key,LPOP/RPOP key
set:SADD key value1 [value2]
zset:ZADD key score value1 [score value2],ZINCRBY key increment member

19.MQ消息发送失败的情况怎么处理:

如果生产者发送消息失败,那么使用重试,如果重试之后,还不行,那么把消息发送到备份交换机,由备份交换机发送消息,如果备份交换机也发送失败,那么设置监控报警,通知程序员去解决这个问题
如果是消费者消费失败,那么使用重试,如果重试之后还不行,那么把消息放入死信队列中,或者放入数据库中,并设置监控报警,通知程序员去解决这个问题

20.join与leftjion 区别

左连接(左外连接):以左表作为基准进行查询,左表数据会全部显示出来,右表如果和左表匹配的数据则显示相应字段的数据,如果不匹配则显示为null 内连接:显示表之间有连接匹配的所有行

21.mysql事务的隔离级别:read uncommit 读未提交 脏读read commit 读已提交 不可重复读repeatable read 可重复读 幻读serializable 串行化

22.哪些场景会导致索引失效:类型转换,字符集不同,索引列使用函数,复合索引没有最左匹配,复合索引排序

23.SQL中聚合函数有哪些?avg(),count() sum()

24.什么是同步?什么是异步?如果有多个任务或者事件要发生,这些任务或者事件必须逐个地进行,如果有多个任务或者事件发生,这些事件可以并发地执行。

25.POST 与GET 区别:GET把参数包含在URL中,POST通过request body传递参数。

26.创建线程的方式:继承Thread、实现Runnable Callable接口

27.Thread 类中的start() 和 run() 方法有什么区别?当你调用run()方法的时候,只会是在原来的线程中调用,没有新的线程启 动,start()方法才会启动新线程。

28.线程的sleep() 和 wait() 区别:sleep是Thread类的方法,wait是Object类中的方法
sleep可以在任何地方使用,wait只能在synchronized方法或块中使用
sleep让出CPU,让线程睡眠一段时间,不释放线程资源,wait让出cpu,释放已占有资源,直到超时或被唤醒

29.创建线程池的参数:1.核心线程数2.最大线程数3.线程空闲时间4.时间单位5.任务队列6.线程工厂7.拒绝策略
线程会一直创建达到核心线程数,超过核心线程数会放到任务队列,任务队列满了扩展最大线程数进行处理。最后走拒绝策略
拒绝策略:1.直接抛异常2.直接丢弃3.丢弃等待时间最久的4.返回给主线程处理

30.自定义线程池核心线程和最大线程数你是如何确定的;IO密集型配置线程是2N,CPU密集型配置线程N+1,(N为CPU核数)

31.线程安全和线程不安全的理解:多个线程执行同一段代码时结果和单个线程执行结果时一致的,线程安全,否则不安全,引起的原因基本都是全局变量,常见的线程安全的类String、HashTable、StringBuffer、java.util.concurrent包下的类

33.Java中常用的加密算法:散列算法MD5 SHA、对称加密3DES、非对称加密 RSA

34.曾经参与过的项目描述:核对所参与项目的真实性,重点了解其在项目内的岗位及职责,针对其负责开发的部分做深入了解,如具体应用的技术,实施过程中的难度等

35.假如一个应用在线上好好的,突然不能用了,怎么找问题?查看进程,端口;查看系统日志,中件件日志;沟通业务操作

1.Java中的两种异常类型是什么?他们有什么区别?Java中有两种异常:受检查的(checked)异常和不受检查的(unchecked)异常。不受检查的异常不需要在方法或者是构造函数上声明,就算方法或者是构造函数的执行可能会抛出这样的异常,并且不受检查的异常可以传播到方法或者是构造函数的外面。相反,受检查的异常必须要用throws语句在方法或者是构造函数上声明。

2.**什么是 singleton class(单例类)?并给出其用法的实际例子:单例类只能有一个实例,必须自己创建自己的唯一实例。使用例子,不需要重复创建对象与初始化的场景

3.使用继承有什么好处?使用继承的主要优点是代码的可重用性,因为继承使子类能够重用其父类的代码。多态性(可扩展性)是另一个好处,允许引入新的功能而不影响现有的派生类。

4.么情况下会发生堆\栈内存溢出: 1.堆内存溢出(OOM)
     1)大对象(从数据库里一次请求了大量的数据)
     2)同时引用的对象过多(大批量的请求、批量任务导致)
     3)内存泄漏(使用了file之类的资源没有关闭回收)
  2.栈内存溢出(StackOverFlow)
     1.方法调用栈过长
     2.线程数过多

5.类在虚拟机中的加载过程:一个类型从被加载到虚拟机内存中开始,到卸载出内存为止,它的整个生命周期将会经历加载(Loading)、验证(Verification)、准备(Preparation)、解析(Resolution)、初始化(Initialization)、使用(Using)和卸载(Unloading)七个阶段,其中验证、准备、解析三个部分统称为连接(Linking)。

知道哪几种主要的JVM参数;1、-Xms:初始堆大小内存
2、-Xmx:最大堆分配内存
3、-Xss:设置单个线程栈的大小
4、-Xmm:设置年轻代的大小
5、-XX:MetaspaceSize设置原空间大小
6、-XX:+PrintGCDetails
7、-XX:SurvivorRatio:设置新生代eden和s0/s1空间的比例
8、-XX:NewRatio:配置年轻代与老年代在堆结构的占比
9、-XX:MaxTenuringThresold:配置垃圾最大年龄

6.对象如何晋升到老年代,完整的GC流程是怎样的:

当 Eden 区的空间满了, Java虚拟机会触发一次 Minor GC,以收集新生代的垃圾,存活下来的对象,则会转移到 Survivor区。
大对象(需要大量连续内存空间的Java对象,如那种很长的字符串)直接进入老年态。
如果对象在Eden出生的话,并经过第一次Minor GC后仍然存活,并且被Survivor容纳的话,年龄设为1,每熬过一次Minor GC,年龄+1,若年龄超过一定限制(15),则被晋升到老年态。即长期存活的对象进入老年态。
老年代满了而无法容纳更多的对象,Minor GC 之后通常就会进行Full GC,Full GC 清理整个内存堆 – 包括年轻代和年老代。
Major GC 发生在老年代的GC,清理老年区,经常会伴随至少一次Minor GC,比Minor GC慢10倍以上。

7.spring的IOC和AOP理解,spring的好处,依赖注入的方式有哪些:IOC:控制反转,把对象的创建权利交给spring,实现方式DI
AOP:面向切面编程,重复的功能抽取出来,动态切入到需要的方法中,减少重复代码,降低耦合度
注入方式:构造方法注入、setter方法注入、接口注入、注解注入

8.spring七个事务传播属性:

1 支持当前事务
REQUIRED:默认的事务传播级别,表示如果当前方法已在事务内,该方法就在当前事务中执行,否则,开启一个新的事务并在其上下文中执行。
SUPPORTED:当前方法在事务内,则在其上下文中执行该方法,否则,开启一个新的事务。
MANDATORY:必须在事务中执行,否则,将抛出异常。

2 不支持当前事务
REQUIRES_NEW:无论当前是否有事务上下文,都会开启一个事务  。如果已经有一个事务在执行 ,则正在执行的事务将被挂起 ,新开启的事务会被执行。
事务之间相互独立,互不干扰。
NOT_SUPPORTED:不支持事务,如果当前存在事务上下文,则挂起当前事务,然后以非事务的方式执行。
NEVER:不能在事务中执行,如果当前存在事务上下文,则抛出异常。

3 嵌套事务
NESTED:嵌套事务,如果当前已存在一个事务的上下文中,则在嵌套事务中执行,如果抛异常,则回滚嵌套事务,而不影响其他事务的操作。

9.Dubbo和Cloud的区别:

dubbo是基于RPC协议的,是更底层的TCP协议,数据不需要经过http协议包装,实践性能更好,主要是接口的远程调用,dubbo中使用zookeeper来做注册中心,所有节点平等,更加关注一致和容错性(CP),当zookeeper中leader挂掉之后会有一个选举(30S-120S),选举期间服务不可用

cloud是基于http协议的,其使用Eureka做注册中心,更加关注可用性和容错性(AP)

10.Ribbon的负载均衡策略有哪些:轮询(RoundRobinRule)、随机(RandomRule)、最少连接数(BestAvailableRule)、带权重的轮询(WeightedResponseTimeRule)、IP哈希(ZoneAvoidanceRule)

11.Ribbon在处理大并发请求时,可以调优的参数:连接超时时间、读取超时时间、是否重试、切换实例的重试的次数

12.Eureka 和 ZooKeeper的区别:(1)Eureka取CAP的AP,注重可用性,Zookeeper取CAP的CP注重一致性。
(2)Zookeeper在选举期间注册服务瘫痪,虽然服务最终会恢复,但选举期间不可用。
(3)eureka的自我保护机制,会导致一个结果就是不会再从注册列表移除因长时间没收到心跳而过期的服务。依然能接受新服务的注册和查询请求,但不会被同步到其他节点。不会服务瘫痪。
(4)Zookeeper有Leader和Follower角色,Eureka各个节点平等。
(5)Zookeeper采用过半数存活原则, reka采用自我保护机制解决分区 。
(6)eureka本质是一个工程,Zookeeper只是一个进程。

13.Zuul和Nginx的区别:Zuul负载均衡实现:采用ribbon+eureka实现本地负载均衡
Nginx负载均衡实现:采用服务器实现负载均衡
Nginx相比zuul功能会更加强大,因为Nginx整合一些脚本语言(Nginx+lua)
Nginx适合于服务器端负载均衡
Zuul适合微服务中实现网关

14.断路器Hystrix的原理及开关几种状态:关闭(Closed)、打开(Open)与半开(Half-Open)
Hystrix通过统计失败的次数来切换状态,在预定的时间内失败次数超过的设定比例,切换到打开状态,所有请求都会降级,打开状态不是永久的,默认休眠5秒,随后进入半开状态,此时会释放一次请求通过,若健康,切换到关闭状态,若失败,继续保持打开状态,再次进入休眠5秒

15.Redis有哪些数据类型:Redis主要有5种数据类型,包括String,List,Set,Zset,Hash,满足大部分的使用要求

16. redis数据过期策略:定期删除:默认每100毫秒扫描一次,随机抽取20个key,删除这20个key中的过期key,过期比例超过1/4,重复步骤
惰性删除:对key操作时,redis会主动检查key是否过期,过期则删除

17.redis数据持久化方式(RDB、AOF):RDB:定时对整个内存做快照,间隔时间长,两次备份之间数据不完整,但备份文件小,恢复速度快,灾难恢复可选择RDB
AOF:记录每一次的写命令,默认每秒一次,数据相对完整,但备份文件大,恢复速度慢,恢复时可以重写AOF

18.MQ消息丢失的原因,怎样规避:怎么处理消息丢失?
1.RabbitMq
(1)生产者把消息发送到MQ时丢失
使用ACK机制,成功发送后会确认,发送失败会有回调。ACK机制是异步的不会阻塞
(2)RabbitMq弄丢了数据
开启消息持久化,消息持久化到磁盘
(3)消费端丢失了消息
消费到消息还没来得及处理的时候,服务挂了。消费成功后手动ack。极端场景下会有处理成功还没来得及手动ack服务挂了或重启了可能会导致重复消费

19如何发现项目中的慢sql,如何优化:

开启并分析慢查询日志:
启用慢查询日志,设置合适的long_query_time,记录执行时间超过阈值的查询。
分析慢查询日志,找出问题SQL,使用工具如pt-query-digest进行深度分析。

使用合适索引:
确保经常用于查询过滤条件和排序的列上有索引。复合索引应按最常用到的列顺序创建。
避免在索引中包含大量重复值的列,这可能会降低索引效率。
使用EXPLAIN分析SQL查询,查看索引使用情况,并根据结果调整索引。

优化查询语句:
减少查询中返回的列数和行数,使用LIMIT限制结果集大小。
避免在WHERE子句中使用复杂的表达式或函数,这可能导致索引失效。
尽量使用JOIN而不是子查询,特别是相关子查询,它们通常更慢。
对于频繁执行但结果不常变的查询,可以考虑使用查询缓存。

优化表结构:
根据数据访问模式合理分区表,比如按时间或ID范围分区。
减少冗余数据,合理使用规范化和反规范化设计。
考虑使用更合适的数据类型,减小存储空间,提高检索效率。

20哪些场景会导致索引失效 :类型转换,字符集不同,索引列使用函数,复合索引没有最左匹配,复合索引排序

21**创建索引的依据是什么:查询where与关联字段

22 sql性能注意事项:sql尽量使用索引,子查询变成left join,exits

23.HTTP的结构:状态码(Status Code),HTTP头部(HTTP Header),主体(Body)

24.**如何建立Socket后,通过什么方法Socket获得流对象?Socket socket=newSocket("127.0.0.1",9999);
OutputStream os=socket.getOutputStream();

25.有一个int类型变量i,开启十个线程每个线程执行i++一万次,i最后对值是多少

小于10万,每个线程对i执行自增操作(i++)实际上分为读取、修改、写回三个步骤。当多个线程同时进行时,这些操作可能会交错执行,导致某些加操作未被正确反映在最终结果中。要确保得到正确的结果,你需要使用线程同步机制,例如Java中的synchronized关键字、AtomicInteger类或者ReentrantLock等。例如,如果使用AtomicInteger,代码可能如下所示:

26.volatile关键字有什么用:

1.保证线程间可见性
2.防止指令重排序
3.不能用于引用对象,当对象中的某个属性改变时别的线程不可见
4.不是原子操作,原子操作是一组操作中间不会被线程切换等打断

指令重排序:
每个线程都有自己的内存,线程之间不可见,不加volatile:线程内存中的数据马上写回堆内存,什么时候从堆内存读不好控制
因为MESI(CPU的缓存一致性协议),多个cpu之间也有自己的缓存,由于不同的线程运行在不同的cpu上,所以这个cpu上修改的值,另一个cpu不能马上知道

使用场景
单例模式使用volatile,超高并发场景避免指令重排序。
INSTANCE = new Singleton(); 
给对象申请内存,成员变量的值为默认值
给对象的成员变量初始化
把内存的内容赋值给INSTANCE(栈内存)
可能重排序造成步骤颠倒
内存屏障保证不指令重排序

27.**HTTPS的安全性是怎么实现的

(1)客户使用https的URL访问Web服务器,要求与Web服务器建立SSL连接。
(2)Web服务器收到客户端请求后,会将网站的证书信息(证书中包含公钥)传送一份给客户端
(3)客户端的浏览器与Web服务器开始协商SSL连接的安全等级,也就是信息加密的等级。
(4)客户端的浏览器根据双方同意的安全等级,建立会话密钥,然后利用网站的公钥将会话密钥加密,并传送给网站。
(5)Web服务器利用自己的私钥解密出会话密钥。
(6)Web服务器利用会话密钥加密与客户端之间的通信

1.jvm调优方式:

JVM调优主要有两种方式:

通过命令行参数进行调优:1.在启动Java应用程序时,可以通过传递特定的JVM选项来调优。例如:

java -Xms512m -Xmx1024m -XX:NewSize=256m -XX:MaxNewSize=512m -XX:PermSize=128m -XX:MaxPermSize=256m MyApplication

这里设置了堆初始大小为512MB,最大堆大小为1024MB,新生代初始大小和最大大小分别为256MB和512MB,永久代(在Java 8及以后是元空间)的初始大小和最大大小分别为128MB和256MB。

2.通过配置文件进行调优:可以创建一个包含JVM调优选项的文件,并在启动Java应用程序时指定该文件。例如,创建一个文件jvm.options:

-Xms512m
-Xmx1024m
-XX:NewSize=256m
-XX:MaxNewSize=512m
-XX:PermSize=128m
-XX:MaxPermSize=256m

启动应用程序时使用该配置文件:

java @jvm.options MyApplication

这两种方式可以根据具体情况选择使用,命令行参数适合临时调优,而配置文件适合长期或默认设置。记得在调优后进行测试和监控,确保调优措施不会影响应用程序的性能和稳定性。

2.java的反射的作用;给定一个类名,就可以通过反射机制来获取类的所有信息,也可以动态的创建对象和编译;

3.内存溢出有哪几种,怎样排查

堆内存溢出(Heap Overflow):
堆内存用于存储动态分配的对象。如果程序频繁创建大量对象,并且没有及时释放(内存泄漏),或者分配的内存超过了堆的最大值(-Xmx设置的值),就会导致堆内存溢出。
常见异常:java.lang.OutOfMemoryError: Java heap space

栈内存溢出(Stack Overflow):
栈内存用于存储方法调用和局部变量。当程序递归调用层级过深、方法调用过于频繁,或者局部变量占用过多栈内存空间时,就会导致栈内存溢出。
常见异常:java.lang.StackOverflowError

永久代/元空间溢出(PermGen space/Metaspace Overflow):
在Java 8之前,永久代(PermGen space)用于存储类的元数据。如果加载了大量的类,或者类的元数据占用的空间超过了永久代的大小,就会导致永久代溢出。
在Java 8及以后,永久代被元空间(Metaspace)所替代。元空间是JVM的本地内存,其大小只受限于本地内存的大小。但即使如此,如果加载的类过多,或者类的元数据占用的内存超过了系统的可用内存,仍然会导致元空间溢出。
常见异常:java.lang.OutOfMemoryError: PermGen space(Java 8之前)或java.lang.OutOfMemoryError: Metaspace(Java 8及以后)

直接内存溢出(Direct Memory Overflow):
直接内存是Java NIO中引入的一种新的内存管理机制,它允许Java程序直接使用本地内存(即堆外内存)。如果直接内存的申请超过了JVM的限制,或者超过了操作系统的限制,就会导致直接内存溢出。

排查Java内存溢出的方法:
查看异常信息:
首先,当程序发生内存溢出时,查看控制台输出的异常信息,确定是哪种类型的内存溢出。
分析堆转储文件(Heap Dump):
对于堆内存溢出,可以使用JVM提供的工具(如jmap、jhat、MAT等)来分析堆转储文件(Heap Dump)。通过分析堆转储文件,可以确定哪些对象占用了过多的内存,进而找到内存泄漏的原因。

分析线程栈(Thread Stack):
对于栈内存溢出,可以通过查看线程栈来确定是哪个方法调用层级过深或占用过多栈空间。可以使用JVM提供的jstack工具来生成线程栈的转储文件。

调整JVM参数:
根据分析的结果,可以尝试调整JVM的启动参数,如增加堆内存的大小(-Xmx)、调整栈的大小(-Xss)等,以缓解内存溢出的问题。

优化代码:
针对内存泄漏的原因,优化代码,减少不必要的对象创建和内存占用,及时释放不再使用的对象。

4.哪些方式可以破坏单例模式,如何避免:1. 多线程环境下未进行创建实例的同步控制会破坏单例。解决方案:使用静态内部类并在内部类中声明单例对象常量。
2. 通过Java反射机制获取单例类的构造方法并调用可以破坏单例。解决方案:在构造方法中判断实例是否已经存在,存在则报错。
3. 通过反序列化可以破坏单例。解决方案:在单例类中定义readResolve方法返回唯一实例,因为Java的序列化机制会通过此方法来获取返回的实例。

5.HashMap的工作原理是什么?Java中的HashMap是以键值对(key-value)的形式存储元素的。HashMap需要一个hash函数,它使用hashCode()和equals()方法来向集合/从集合添加和检索元素。当调用put()方法的时候,HashMap会计算key的hash值,然后把键值对存储在集合中合适的索引上。如果key已经存在了,value会被更新成新值。

6.在Java中,对象什么时候可以被垃圾回收?当对象对当前使用这个对象的应用程序变得不可触及的时候,这个对象就可以被回收了。

7.SpringBoot框架的自动装配原理

SpringBoot自动装配的核心在于spring-boot-autoconfigure模块,入口类的@SpringBootApplication注解中包含了@EnableAutoConfiguration注解,该注解通过@Import注解引入的AutoConfigurationImportSelector类会在应用启动时扫描所依赖的starter,并通过starter中spring.factories定义的自动配置列表定位相关的配置类,进而将这些配置类中使用@Bean注解创建的Java Bean交给IoC容器托管,或者去配置类上的@ComponentScan注解声明的package下查找需要交给IoC容器托管的Bean。

8.Dubbo和Cloud的区别:

dubbo是基于RPC协议的,是更底层的TCP协议,数据不需要经过http协议包装,实践性能更好,主要是接口的远程调用,dubbo中使用zookeeper来做注册中心,所有节点平等,更加关注一致和容错性(CP),当zookeeper中leader挂掉之后会有一个选举(30S-120S),选举期间服务不可用

cloud是基于http协议的,其使用Eureka做注册中心,更加关注可用性和容错性(AP)

9.springcloud通过feign调用的详细过程:

声明接口:在Spring Cloud项目中,你首先通过声明式的方式定义一个接口,这个接口通常使用@FeignClient注解进行标记,并指定要调用的服务名称。Feign会根据这个接口动态地创建实现类,这个实现类会负责与服务提供者进行通信。

配置Feign:在Spring Boot的启动类上,你通常需要使用@EnableFeignClients注解来启用Feign的功能。这个注解会触发Spring Cloud的自动配置机制,为Feign创建必要的Bean和配置。

服务发现:Feign会集成Eureka等服务发现组件,用于获取服务提供者的地址信息。当你通过Feign的客户端接口调用服务时,Feign会首先从Eureka等注册中心获取服务提供者的地址列表。

负载均衡:如果服务提供者存在多个实例,Feign会内置负载均衡器(如Ribbon)来选择合适的服务实例进行调用。负载均衡器会根据一定的策略(如轮询、随机等)来选择服务实例。

发送请求:Feign会根据你定义的接口和参数信息,构造HTTP请求,并通过HTTP客户端(如Apache HttpClient、OkHttp等)将请求发送给选定的服务提供者实例。

处理响应:服务提供者处理请求后,会返回HTTP响应。Feign会接收这个响应,并对其进行解码和处理,然后将结果返回给调用者。

10.对Ribbon 源码的了解:Ribbon是通过LoadBalancerInterceptor类在对RestTemplate的请求进行拦截然后从注册中心根据服务id获取服务列表,随后利用负载均衡算法得到真实的服务地址信息,替换服务id。

11.分布式缓存,分布式锁,分布式框架,分布式调度,分布式消息队列有那些:分布式分为分布式缓存(Redis)、分布式锁(Redis或Zookeeper)、分布式服务(Dubbo或SpringCloud)、分布式服务协调(Zookeeper)、分布式消息队列(Kafka、RabbitMq)

12.对Spring框架Bean生命周期的了解

1、解析xml配置或者注解的类,得到BeanDefinition;
2、通过BeanDefinition反射创建Bean对象(实例化Bean对象)。
3、对Bean对象进行属性填充
4、回调实现Aware接口的方法,比如BeanNameAware
5、调用BeanPostProcessor的初始化前方法;
6、调用init初始化方法(如果有的话);
7、调用BeanPostProcessor的初始化后方法,此处会进行AOP;
8、将创建好的Bean对象放入一个Map中;
9、业务中使用Bean对象就从Map中获取;
10、Spring容器关闭时调用DisposableBean的destory方法销毁Bean对象;

13.使用AOF持久化文件过大恢复数据慢,怎样优化:

AOF重写(Rewrite):
Redis提供了BGREWRITEAOF命令或配置自动触发AOF重写。重写会创建一个新的AOF文件,其中只包含恢复当前数据集所需的最小命令集。这可以显著减少AOF文件的大小,从而加快恢复速度。

调整AOF重写触发条件:
可以通过配置auto-aof-rewrite-percentage和auto-aof-rewrite-min-size来调整AOF重写的触发条件。前者定义了AOF文件增长率超过多少百分比时触发重写,后者定义了AOF文件最小大小达到多少字节时触发重写。

优化AOF写入策略:
Redis提供了三种AOF写入策略:always、everysec和no。其中,everysec是默认配置,它每秒将缓冲区中的命令写入磁盘一次。在高写入负载下,可以考虑将策略调整为no,让操作系统来决定何时将缓冲区的数据刷新到磁盘,但这会增加数据丢失的风险。

14.redis集群模式(主从、哨兵*、cluster)及数据同步过程*

数据同步过程:
1.slave节点请求增量同步
2.master节点判断replid,发现不一致,拒绝增量同步
3.master将完整内存数据生成RDB,发送RDB到slave
4.slave清空本地数据,加载master的RDB
5.master将RDB期间的命令记录在repl_baklog,并持续将log中的命令发送给slave
6.slave执行接收到的命令,保持与master之间的同步

15.redis怎样实现分布式锁

redis使用setNX来是实现分布式锁,表示当key不存在的时候加锁,并设置过期时间(关注锁续期的实现及怎样保证释放锁的是当前线程)

16.redis数据过期策略:定期删除:默认每100毫秒扫描一次,随机抽取20个key,删除这20个key中的过期key,过期比例超过1/4,重复步骤
惰性删除:对key操作时,redis会主动检查key是否过期,过期则删除

17.消息队列出现消息积压,有哪些原因?怎么解决?出现消息积压,可能是因为消费的速度太慢。
扩容消费者。之所以消费延迟大,就是消费者处理能力有限,可以增加消费者的数量。
扩大分区。一个分区只能被消费者群组中的一个消费者消费。消费者扩大,分区最好多随之扩大

18.读已提交和可重复读隔离级别是通过什么实现的 mvcc多版本并发控制
不使用锁,实现并发的读写不冲突
mvcc只支持rc和rr级别
mvcc由三部分组成
1.隐藏字段 trx_id事务id; roll_pointer 回滚指针,指向回滚日志; row_id 行标识,隐藏ID;
2.undolog
3.read view 事务中的快照读时生成,字段有数据的事务范围,最小的事务id,最大的事务id,当前事务的id
rr级别的事务 read view不重新生成,所以不会产生不可重复读和幻读,有特例是,其他事务新增了数据,当前事务又修改了新增的数据(当前读),再次select会造成幻读
rc级别的事务 每次select会重新生成read view
并发去修改某一条数据时会形成版本链
开启事务后第一次查询已经跟数据建立绑定关系

19.mysql索引的数据结构是什么?为什么使用B+树?索引数据结构
二叉树 数据一直是有序插入结构会接近于链表
avl树 为了保持平衡会导致频繁旋转,深度过深
红黑树 深度过深
b树 由于索引和数据都放在树形节点中,每个节点大小是16K,导致深度过深
b+树 数据放在最底层的叶子结点中,节省了树形每个层级的存储空间,避免了树层级过深

20.ThreadLocal是什么:它提供了一种机制,使得每个线程都可以拥有某个变量的独立副本,即使多个线程并发访问这个变量,每个线程看到的都是自己独有的、不受其他线程影响的变量值。简而言之,ThreadLocal保证了变量在线程间的隔离性,有助于避免多线程环境下的数据同步问题。

21.ThreadLocal为什么使用了弱引用

ThreadLocalMap假设Entry对象中的k是强引用,也就是红线部分是强引用的话,由于Entry对象还有一个强引用作用于ThreadLocal对象,即使设置了threadLocal=null,垃圾回收器也不会对ThreadLocal对象进行回收。从而造成内存泄漏。

弱引用在gc的时候会被回收,如果弱引用指向的对象有一个强引用同时存在,强引用消失,弱引用会被回收
强:常见的引用,引用消失,GC时被回收
软:应用于缓存,Tomcat和memberCache就使用了软引用,将大图片或大量数据读到内存中;内存不够的时候才会被回收
弱:ThreadLocal,防止内存泄漏;遇到GC就会被回收
虚:堆外内存的管理,get不到值,GC时通知ReferenceQueue进行内存回收;DirectByteBuffer就是通过虚引用对堆外内存进行释放

22.Netty 是什么?Netty 是一款基于 NIO(Nonblocking I/O,非阻塞IO)开发的网络通信框架,对比于 BIO(Blocking I/O,阻塞IO),他的并发性能得到了很大提高。难能可贵的是,在保证快速和易用性的同时,并没有丧失可维护性和性能等优势。

23.高并发下单扣减库存,怎样保证扣减的库存数正确:1.数据库层面
update product set stock=stock-1 where id=1 and stock-1>0
2.分布式锁
3.使用数据库乐观锁

24.服务器cpu突然飙升怎样排查问题

使用top命令:
在Linux服务器上,使用top命令可以实时查看各个进程的CPU使用情况。观察是否有某个Java进程的CPU占用率特别高。
通过top命令找到占用CPU高的Java进程PID(进程ID)。

定位线程:
使用ps -mp pid -o THREAD,tid | sort -r命令,根据Java进程的PID找到占用CPU高的线程ID。
将线程ID转换为16进制格式,使用printf "%x\n" tid命令。

获取线程堆栈信息:
使用jstack pid | grep tid -A 50命令,将Java进程的PID和转换后的线程ID(16进制)作为参数,获取线程堆栈信息。
分析堆栈信息,定位导致CPU占用高的代码段。

25.类加载器是什么,什么场景需要自定义类加载器

自定义类加载器则是用户根据特定需求自行实现的ClassLoader子类。在以下场景中,可能需要自定义类加载器:

隔离加载上下文:在某些框架或应用服务器中,为了实现类的隔离,每个模块或应用可能需要有自己的类加载器,以防止类名冲突。

动态加载类:当应用程序需要在运行时从数据库、网络或其他非标准来源加载类时,自定义类加载器可以提供这种灵活性。

加密和解密类:为了保护代码不被轻易阅读或修改,可以通过自定义类加载器对类文件进行加密,并在加载时解密。

热部署和模块化:在需要支持热替换(Hot Swap)或模块动态更新的系统中,自定义类加载器可以用来卸载和重新加载特定的类或模块,而不需要重启整个应用。

实现特殊类加载逻辑:例如,加载非.class格式的字节码,如从JSP文件生成的类,或者实现自己的验证逻辑来增强安全性。

26.java中有哪些垃圾回收算法和垃圾回收器

垃圾回收器
1.Serial
单线程,回收时会stw,使用复制算法,轻量级,占用资源小适合客户端
2.Serial Old
是Serial收集器的老年代版本,单线程收集器,使用标记整理算法。作为CMS收集器的后备方案
3.Parale Scavenge
跟Parallel收集器很类似,提升吞吐量
4.Parallel Old
Parallel Scavenge收集器的老年代版本。使用多线程和“标记-整理”算法
5.ParNew
Serial收集器的多线程版本,区别主要在于它可以和CMS收集器配合使用
6.CMS
初始标记: 暂停所有的其他线程(STW),并记录下gc roots直接能引用的对象,速度很快。
并发标记: 并发标记阶段就是从GC Roots的直接关联对象开始遍历整个对象图的过程, 这个过程耗时较长但是不需要停顿用户线程, 可以与垃圾收集线程一起并发运行。因为用户程序继续运行,可能会有导致已经标记过的对象状态发生改变。
重新标记: 重新标记阶段就是为了修正并发标记期间因为用户程序继续运行而导致标记产生变动的那一部分对象的标记记录,这个阶段的停顿时间一般会比初始标记阶段的时间稍长,远远比并发标记阶段时间短。主要用到三色标记里的增量更新算法(见下面详解)做重新标记。
并发清理: 开启用户线程,同时GC线程开始对未标记的区域做清扫。这个阶段如果有新增对象会被标记为黑色不做任何处理(见下面三色标记算法详解。
并发重置:重置本次GC过程中的标记数据。
缺陷:
并发清理容易产生浮动垃圾,只能等待下一次回收清理
老年代放不下新产生的对象,会触发SerialOld,会stw,回收速度极慢
1.避免过多的内存碎片,-XX:CMSFullGCsBeforeCompaction 默认为0 指的是经过多少次FGC才进行压缩
2.Floating Garbage 浮动垃圾过多和PromotionFailed(新的对象不能往老年代装了),降低触发cms回收的阀值

7.G1
G1收集器充分利用了多核处理器的优势,通过并行处理多个区域来提高垃圾收集的效率。同时,它还可以在应用程序线程运行时并发地执行部分垃圾收集任务,从而减少了应用程序的停顿时间
可以有多个线程在不同区域同时进行回收
年轻代和老年代的各个区域不要求是连续的,也不需要固定大小和固定数量
可以在用户指定时间内完成垃圾回收

缺点:
1.G1收集器为了跟踪和管理堆内存中的各个区域,需要占用一定的内存空间来存储相关信息,还有跨代引用的记录,维护成本较高
2.不适用于小内存,小内存分配的每个Region空间较小,导致频繁回收
3.跨块引用问题

27.redis内存满了又放入新的key会发生什么?

会触发淘汰策略
1.不淘汰数据,缓存被写满后,有写入请求直接报错
2.volatile-ttl:在设置了过期时间的键值对中,移除即将过期的键值对
3.volatile-random:在设置了过期时间的键值对中,随机移除某个键值对
4.volatile-lru:在设置了过期时间的键值对中,移除最近最少使用的键值对
5.volatile-lfu:在设置了过期时间的键值对中,移除最近最不频繁使用的键值对
6.allkeys-random:在所有键值对中,随机移除某个key
7.allkeys-lru:在所有的键值对中,移除最近最少使用的键值对
8.allkeys-lfu:在所有的键值对中,移除最近最不频繁使用的键值对
默认是allkeys-lru
选择哪种策略主要是看能否区分key的访问频率,如果所有key访问频率很平均使用allkeys-random比较合适

28.哪些场景会发生事务超时,怎样排查

MySQL中事务超时主要发生在以下几种场景:

锁等待超时:当一个事务试图获取已被另一个未完成事务锁定的资源时,它会进入等待状态。如果等待时间超过了MySQL配置的innodb_lock_wait_timeout参数值(默认通常是50秒),事务会抛出“Lock wait timeout exceeded”错误。

事务执行超时:开启事务后调用外部系统的接口,或其他服务的接口时间过长导致超时。

死锁:两个或多个事务互相等待对方持有的锁,形成循环等待,这时MySQL的死锁检测机制会介入,其中一个事务会被回滚,导致超时。

排查事务超时的方法:

 检查慢查询日志:查看MySQL的慢查询日志,找出执行时间长的SQL语句,这些可能是导致锁等待或执行超时的根源。
 使用SHOW ENGINE INNODB STATUS;:此命令可以显示InnoDB引擎的状态,包括最近发生的锁等待事件和死锁信息,有助于分析锁等待的具体情况。
 监控InnoDB锁信息:通过INFORMATION_SCHEMA.INNODB_TRX视图,可以查看当前运行的事务、事务开始时间、是否锁定了表或行等信息,帮助定位哪个事务持有锁。

29.什么是innodb的页,有什么作用:select * from test where ID=7; 减少磁盘IO,如果正常查询,需要一条一条的数据查出来,在内存中比对id是否为1。一次查出一页数据在内存中比对
页的组成:页头(上一页,下一页指针) 页目录 数据区域
索引页 指向数据页

30.线程池中的线程执行任务,任务抛出异常,线程会被销毁吗?

会被销毁并新开启一个线程,抛出异常会导致线程执行一串finally跳出while循环
为什么要销毁线程?自定义线程工厂可以重写线程异常处理器

31.ReentrantLock的公平锁和非公平锁有什么区别

1.公平锁
先将线程自己添加到等待队列的队尾并休眠,当某线程用完锁之后,会去唤醒等待队列中队首的线程尝试去获取锁,锁的使用顺序也就是队列中的先后顺序,在整个过程中,线程会从运行状态切换到休眠状态,再从休眠状态恢复成运行状态,但线程每次休眠和恢复都需要从用户态转换成内核态,而这个状态的转换是比较慢的,所以公平锁的执行速度会比较慢。
2.非公平锁
当线程获取锁时,会先通过 CAS 尝试获取锁,如果获取成功就直接拥有锁,如果获取锁失败才会进入等待队列,等待下次尝试获取锁。这样做的好处是,获取锁不用遵循先到先得的规则,从而避免了线程休眠和恢复的操作,这样就加速了程序的执行效率

32.java nio核心组成部分与作用?

NIO主要有三大核心部分:Channel(通道),Buffer(缓冲区), Selector。NIO基于Channel和Buffer(缓冲区)进行操作,数据总是从通道读取到缓冲区中,或者从缓冲区写入到通道中。Selector(选择区)用于监听多个通道的事件(比如:连接打开,数据到达)。因此,单个线程可以监听多个数据通道。

33.Netty 是什么?Netty 是一款基于 NIO(Nonblocking I/O,非阻塞IO)开发的网络通信框架,对比于 BIO(Blocking I/O,阻塞IO),他的并发性能得到了很大提高。难能可贵的是,在保证快速和易用性的同时,并没有丧失可维护性和性能等优势。

34.数据量很大的表添加列执行速度慢怎样解决?

使用ALTER TABLE的ALGORITHM=INPLACE和LOCK=NONE选项:
MySQL 5.6及以上版本支持在线DDL操作,其中ALGORITHM=INPLACE和LOCK=NONE可以尽量减少对表的锁定,允许在添加列时其他查询仍然可以访问表。但请注意,并非所有类型的ALTER TABLE操作都支持这些选项,具体是否可用取决于你要执行的操作类型。
ALTER TABLE your_table_name 
ADD your_column_name column_type 
ALGORITHM=INPLACE LOCK=NONE;

使用PT-Online-Schema-Change工具:
Percona Toolkit中的pt-online-schema-change工具可以在几乎不影响线上服务的情况下,安全地在线更改表结构。它通过创建一个新表,然后在后台同步旧表的数据到新表,并在完成后原子性地切换表名,从而减少了锁的时间。

分批操作:
如果上述方法都不适用或效果有限,且表极其庞大,可以考虑手动分批操作。例如,先创建一个新表,包含原有列和新列,然后逐步迁移数据,最后替换原表。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值