一.Java基础
1.1 Java中的基本数据类型都有什么?
整型:byte int short long
浮点型:float double
布尔型: boolean
字符型: char
1.2 String类可以被继承吗?
不能,在java中 String类的创建有final修饰符,而final修饰的类不可以被继承,所以String类无法被继承
1.3 Java面向对象的特性是什么?
多态,继承,封装
继承:一个类可以继承一个类的属性和功能,同时也可以实现自己的功能,被继承的称为父类,继承的是子类
多态:不同类的对象调用同一个方法,产生不同的结果
封装:将某个对象的属性和功能结合为一个独立的整体,并尽可能隐藏对象的内部实现细节。封装的目的在于提高代码的安全性、可维护性和可重用性。
1.4 Java中的反射
在JAVA命令运行状态中,除运行的类之外其余任意的类都可以知道运行类的方法和属性,且可以调用其中的一个方法
反射的使用场景:
框架:反射重要的用途就是开发各种通用框架,例如Spring SPringMVC这种通用框架都是配置化的,这些框架需要根据配置文件运行时加载不同的类和方法,为了保证框架随时可用
1.5 Java中的异常是怎么处理的?
Java将所有的错误封装为一个对象,抛出异常,捕获异常。
这是异常的所有类
Throwable代表所有异常的父类(超类)
Throwable下分为两个大类一个是Error 一个是Exception
Error:这种错误主要是指程序运行时系统内部的错误或者是系统的资源耗尽错误,
Exception:RuntimeException(运行时异常)和CheckedException(已检测异常)
RuntimeException:
NullPointerException:空指针引用异常
ClassCastException:类型转换异常
IllegalArgumentException:传入非法参数异常
ArithmeticException:算术异常
IndexOutOfBoundsException:下标越界异常
CheckedException
IO异常:IOException
SQL异常:SQLException
1.6 JDBC连接数据库的原理是什么?
首先需要获取JDBC的驱动(使用Class.forName()),然后把驱动加载到DriverManger中(DriverManger是JDBC的一个api),使用DriverManger类中的方法(getConnection)与数据库创建连接。
二.Mysql
2.1 如何定位mysql中的慢查询?
mysql中的日志可以记录慢查询的语句,在慢查询日志里设置一个参数,如果某个语句的执行时间超过了这个参数,那么它就会被记录在慢查询日志里。(需要手动开启慢查询日志)
2.2 SQL语句执行的很慢,应该怎么办?
采用mysql中的explain指令查看sql执行语句的全部参数,一是通过在参数里查看key和key_len可以知道这条sql语句是否命中了索引(如果查询语句没有命中索引,速度就会下降),二是查看这条语句的type,type可以告诉你这条语句的执行方式。
2.3 什么是索引?有什么作用?
索引在mysql中是指帮助mysql高效获取数据的一种数据结构,索引包含:普通索引,唯一索引,全文索引,单/多列索引,组合索引。它帮助数据库降低检索数据的时间,降低数据库的IO成本,同时根据索引列对数据进行排序,降低了手动排序数据的成本,也降低CPU的消耗。.
2.4 索引的底层数据结构了解过嘛?(索引在什么时候会失效)
索引的底层数据结构是B+树。
2.5 B树和B+树的区别是什么呢?
首先B树是一种多路平衡查找树,而B+树是它的变体,B树的节点存储的是键值和数据,B+树的内部节点只存储键值(索引),数据存储在叶子节点,查询时,B+树的查询效率更稳定一些。
二是在进行一些数据的范围查询时,B+树比B树效率高,因为B+树的叶子节点是一个双向链表,每个叶子节点通过链指针相连,所以范围查询的效率B+树效率要比B树高
三是由于B+树的内部节点不存数据,那么每个节点可以查询的范围就更大,减少磁盘I/O.
2.6 解释一下redo-log和undo-log
redo-log是重做日志,主要针对InnoDB存储引擎,记录数据更改操作的物理日志,当系统出现问题时,可以通过redo-log恢复未完成的事务。
undo-log是回滚日志,同样是针对InnoDB存储引擎,undo-log中存放着事务执行过程中原始的数据,它的作用是回滚事务和实现多版本并发控制(MVCC)
2.7 Mysql的锁机制?
根据加锁的范围不同分为:全局锁、表级锁、行级锁
全局锁是锁定整个数据库,一般用于保护数据库的完整性。
表级锁是锁定当前操作的数据表,用于需要读取整个表而不需要频繁更新的场景。
行级锁是锁定当前操作表中的一行数据,适用于InnoDB存储引擎,以及高并发、更新操作频繁的场景.
根据操作的类型不同分为:读锁(共享锁)和写锁(排他锁)
读锁是允许多个事务同时读取同一资源,但其他事务无法修改,此时其他事务看到的数据是上00锁时的数据. 写锁是阻止其他事务对已上锁的数据进行读写,直到写锁释放。
2.8 MVCC是什么?
MVCC全称多版本并发控制,意思是维护一个数据的多个版本,使读写操作没有冲突。它底层由三个部分实现:一是隐藏字段,二是undo-log,三是readView读视图。
隐藏字段指的是在mysql中给每个表都设置了隐藏字段,有一个是trx_id(事务id),记录每一次操作的id,这个id是自增的;另一个字段是roll_pointer(回滚指针),指向上一个版本的事务版本记录地址。
undo-log就是记录老版本的数据,它会形成一个版本链,记录不同事务修改某行数据的版本,并通过回滚指针形成一个链表。
readView解决的是一个事务查询选择版本的问题,在内部定义了一些匹配规则和当前的一些事务id判断该访问那个版本的数据,不同的隔离级别快照读是不一样的,最终的访问的结果不一样。如果是rc隔离级别,每一次执行快照读时生成ReadView,如果是rr隔离级别仅在事务中第一次执行快照读时生成ReadView,后续复用。
2.9 介绍一下Mysql的主从同步(复制)
Mysql的主从同步指的是数据可以从数据库主节点复制到一个或多个数据库从节点中去,数据库默认的主从同步方式是异步复制,好处是从节点不需要一直访问主数据库来获取数据。
主从同步可以用于数据实时备份,当系统中某个节点发生故障,可以随时进行切换。 还可用于读写分离,主库负责写,从库负责读,这样即便主库被锁,只靠读取从库也可以保证业务正常运行
主从复制的核心主要是二进制日志(binlog):binlog记录了所有的数据定义1语言和数据操纵语言,但不包括数据查询语句。
主从复制的步骤:1.主库事务提交,上传数据变更记录给binlog。2.从库读取binlog,写入到从库的relaylog(中继日志)中。3.从库重新执行relaylog中的语句。
2.10 Mysql的分库分表
随着系统的运行,存储在数据库中的数据量会越来越大,这时候就需要分库分表。
拆分策略一般分为水平和垂直。
垂直分库是指以表为依据,根据业务将不同表拆分到不同库中
垂直分表是指以字段为依据,根据字段属性将不同字段拆分到不同表中
水平分库是将一个库的数据拆分到多个库里
水平分表是将一个表的数据拆分到多个表里
2.11 什么是事务?并发事务会导致什么后果?
事务是指一个由一条或者多条SQL组成的一个整体,事务中的操作,要么全部成功,要么全部失败。 事务的四大特性是原子性、一致性、隔离性、持久性(ACID).
并发事务会导致脏读、不可重复读、幻读。
脏读:一个事务读到另一个事务还未提交的数据。
不可重复读:一个事务先后读取同一条数据,但两次结果不用,称为不可重复读。
幻读:一个事务按照条件查询时,没有查询到对应的数据行,但在插入数据时,发现这行数据存在,好像出现了"幻影"。
2.12 怎么防止并发事务导致的后果?
处理并发事务问题,可以对事务进行隔离:
read uncommitted:读未提交 解决不了任何问题但效率最高
read committed:读已提交(oracle默认) 防止脏读
repeatable read:可重复读(MySql默认) 防止脏读、不可重复读
serializable:可串行化 防止所有问题(脏读、不可重复读、幻读)
三.Redis
3.1 Redis的基本数据类型
hash型 集合set型 字符串string型 列表list型 有序集合zset型
hash型主要用于存储用户信息,便于快速访问和修改
set用于实现标签、好友关系等需要快速判断成员关系的场景
string用于缓存、计数器、分布式锁等简单键值存储
list型用于实现消息队列、任务队列、社交应用的队列
zset用于排行榜等需要排序的场景
3.2 Redis作为缓存时,可能会出现什么问题?怎么解决?
可能会出现缓存击穿、缓存穿透、缓存雪崩等问题
缓存击穿是指给某一个key设置了过期时间,当key过期的同时,针对key的大量请求出现,这些并发请求可能会瞬间把数据库压垮+
解决:
一:使用Redis的Setnx设置一个互斥锁,如果一个请求查询缓存且未命中时(因为key过期了),此时它获取到这个互斥锁,然后根据这个请求查询数据并重新缓存数据,操作完成后再释放锁,这样可以保证不会有大量的并发把数据库冲垮。不过缺点是性能很差。
二:在设置key的时候,再设置一个过期时间字段一块存入到缓存中,不设置key过期时间,当查询请求来的时候,从redis中把数据取出然后判断是否过期,如果过期就从数据库里拿一个新的数据出来同步,这个请求正常返回,但返回的数据不是最新的数据,
缓存穿透是指当在一个数据库里查询一个不存在的数据时,mysql查询不到数据也不会直接写入缓存,会导致每次请求都去数据库里找,可能会导致数据库崩溃。
解决:
一:缓存一个空数据,即使数据的value不存在,也缓存起来。
二:使用布隆过滤器过滤空数据
缓存雪崩是指同一时间内大量的key同时失效或者Redis服务器宕机,大量的请求就会给到数据库,数据库的压力就会很大。
解决: 一:设置随机失效时间
二:利用Redis集群服务
三:给缓存业务添加降级限流策略
3.3 什么是Redis的持久化?怎么实现的?
Redis的持久化是指将Redis内存中的数据保存至磁盘,以免出现因系统故障导致的数据丢失,当Redis服务器重启时,可以通过持久化文件来恢复数据。
持久化有两种方式实现:RDB和AOF
RDB: Redis将内存中的数据周期性地保存到磁盘上的二进制文件中,这个文件就是RDB文件。当Redis故障重启后,从RDB文件中读取数据(相当于一个数据快照)
AOF: AOF相当于是一个日志,它记录了Redis中的每一个写操作。
RDB与AOF的区别
RDB占用空间小读取数据时快速但不能保证数据完整性且资源占用多
AOF占用空间大读取数据慢但数据完整性比RDB要好占用的资源也少,所以AOF优先级高一些。
如果AOF占用的空间过大会影响性能这时候会采用AOF重写机制,根据Redis进程内的数据生成一个新的AOF文件,该文件只包含当前有效和存在的数据的写入命令,而不是历史上所有的写入命令。这样可以压缩和优化AOF文件的内容,减少冗余和无效的命令,提高数据的存储效率和恢复速度。
3.4 Redis的数据过期策略
Redis有两种过期策略分别是惰性删除和定期删除
惰性删除就是设置key过期时间后不对key做任何操作,等需要这个key的时候,拿出来判断一下到了过期时间没,如果过期了就删掉,没过期就返回key。
定期删除是每隔一段时间,就对一些key进行检查,删除里面过期的key。
一般Redis是两种过期策略配合使用。
3.5 Redis的数据淘汰策略
Redis如果内存不够用的时候再向Redis内存添加数据,此时就会根据Redis的数据淘汰策略去淘汰一些数据,Redis一共有八种淘汰策略(默认是noeviction),最为主要的是依据LRU和LFU算法的四种策略,分别是allkeys-lru、allkeys-lfu、volatile-lru、volatile-lfu。
lru算法:最近最少使用,用当前时间减去最后一次访问时间,得出来的值越大的优先级越高(访问的越早越会被删)
lfu算法:最少频率使用,统计每个key的使用频率,少的淘汰优先级高。(使用的越少就越会优先被删)
如果业务中有置顶的需求,可以使用volatile-lru策略,对需要置顶的数据不设置TTL,这些数据就一直不会被删除,只会淘汰其他设置过期时间的数据
3.6 redis的主从同步和主从同步的流程
Redis的主从同步实际就是一个数据复制的流程,主要是使一个节点(主)可以将它的数据复制给其他的节点(从),以此来提高数据可用性和读取性能。
主节点主要负责写数据和读数据,从节点负责读数据不能写(分担主节点读取压力),实现读写分离。
同步流程是从初始同步开始的,启动从节点时向主节点发送一个PSYNC命令,请求进行同步,之后主节点响应,开始进行数据复制,在传输期间从节点处于同步状态。如果数据发生变化(主节点发生写操作),会开启增量同步,从节点发送请求时,主节点会判断这次请求的replid是否是和第一次发送请求的replid一致,不一致就会从缓冲区中取出新增的数据发送给从节点,这就是增量同步。
3.7 redis集群脑裂,该怎么解决呢?
Redis的集群脑裂一般发生在主节点挂了之后,主节点挂了之后,哨兵发现没有主节点了就会选举一个新的主节点,此时重启旧的主节点,就会出现有两个主节点的情况,这样会导致客户端会一直给旧的主节点同步数据,而新主节点无法同步数据,哨兵会自动把旧主节点变为从节点,这样就会损失大量数据。
解决:设置最少的从节点,比如主节点至少有一个从节点才能开始同步数据。或者设置主从数据复制的延迟时间,没到这个时间就拒绝复制请求,
四.消息队列
4.1 什么是kafka(Kafka里有什么)
Apache Kafka是一个开源的分布式流处理平台,主要用于高吞吐量的消息传递和数据流处理。
它由Producer、Consumer、Broker、Topic、Partition、Offset组成
Producer生产者:发送消息给主题Topic,或者发送给特定的分区Partition
Consumer消费者:读取消息。
Broker代理:kafka集群中的每一个服务器称为Broker,负责存储和传递消息,Broker接受Producer的消息并存储在Partition里
Topic主题:消息的分类,每个Topic可以有多个Partition。Producer可以将消息发送给特定的Topic,然后由Consumer读取消息。
Partition分区:主题的分片,允许kafka并行处理消息,每个partition是有序的
Offset偏移量:每个消息在分区中的唯一标识符,Consumer用它来跟踪消息。
4.2 什么是RabbitMQ
RabbitMQ和Kafka一样是主要用于在分布式系统中传递消息.
它的组件有:Producer、Queue、Consumer、Exchange。
Producer生产者发送消息到Queue队列中,Consumer消费者首先从Queue中接收消息。
Exchange交换机首先接受消息根据不同类型放到不同Queue中:Direct根据路由键直接发送消息、Fanout将消息广播到所有绑定的队列、Topic根据主题模式路由消息、Headers基于消息的头部属性进行路由。
4.3 RabbitMQ如何保证消息不丢失
一:开启生产者确认机制,确保生产者的消息能达到队列,具体原理是生产者发送消息给RabbitMQ后,RabbitMQ会向生产者返回一个确认信号,通过确认机制可以确保消息发送成功。
二:开启持久化功能:消息持久化:发布消息时,通过将消息标记为durable来指定消息持久化
队列持久化:创建队列时直接把队列设置成持久化 hannel.queue_declare(queue='队列名称', durable=True)
交换机持久化:创建交换机时
public DirectExchange simpleExchange(){ //三个参数代表交换机名称、是否开启持久化、当没有queue绑定时是否自动删除此交换机
return new DirectExchange("simple.Exchange",ture,flase); }
三:消费者确认机制:当消费者处理消息后向MQ发送一个ack回执,MQ收到ack回执后才会删掉消息
4.4 RabbitMQ如果出现消息的重复消费问题该怎么做?
引发这种情况的原因一般是:网络抖动,消费者挂了
解决:给每条消息设置一个唯一的标识id 或使用分布式锁、数据库锁等。
4.5 解释一下RabbitMQ延迟队列(死信交换机)
一个队列中的消息可能会出现以下状况:消息过期了但没有消费者消费那么这个消息会成为死信、消息存在的队列满了,那最早的消息可能会成为死信。如果该队列指定了一个死信交换机,那么这些消息就会被传递到死信交换机中。
延迟队列是通过死信交换机和TTL实现的,在死信交换机绑定多个队列然后通过设置消息的TTL来达到延迟队列的效果。
4.6 如果有百万消息堆积在MQ,如何解决?
当消费者处理消息的速度跟不上生产者发送消息的速度,那么就会发生消息堆积。
解决:增加更多消费者
在消费者内部开启线程池加快消费者的处理消息速度
扩大queue容积,可以使用MQ惰性队列,特性是接受消息后直接存入磁盘而非内存,当消费者要读取消息时才会从磁盘中加载到内存,而且支持百万条数据的存储。
4.7 RabbitMQ的高可用机制
使用MQ集群来保证高可用
4.8 Kafka如何保证消息不丢失
消息消失的情况:
生产者发送消息到Brocker丢失:设置消息异步发送,消息重试可解决 消息在Brocker中存储丢失:设置确认机制ack,消息到Brocker中后Brocker会给Kafka一个确认信息 消费者从Brocker接收消息丢失:Kafka的消息消费都是按照offset标记然后消费者再进行消费的,消费者默认自动按期提交已经消费的offset,默认是每5s一次如果发生消息丢失,可以把自动提交改为手动提交,当消费成功以后再报告给broker消费的位置。
4.9 Kafka如何保证消息的顺序性
kafka默认存储和消费消息,是不能保证顺序性的,因为一个topic里数据可能存储在不同的分区中,每个分区都有一个按照顺序的存储的偏移量,如果消费者关联了多个分区不能保证顺序性。
但是把消息都存储到一个分区下就可以了,设置生产者可以在发送消息的时候指定分区号或者发送消息的时候按照相同的业务设置相同的key(默认情况下分区通过key的hashcode值来选择分区,hash如果一样分区也一样)
4.10 Kafka的高可用机制
和MQ一样 kafka的高可用也是由kafka集群实现的
kafka集群指的是由多个broker实例组成,即使某一台宕机,也不耽误其他broker继续对外提供服务
kafka还有一个复制机制也可以保证高可用:一个topic有多个分区,每个分区有多个副本,有一个leader,其余的是follower,副本存储在不同的broker中;所有的分区副本的内容是都是相同的,如果leader发生故障时,会自动将其中一个follower提升为leader。
4.11 Kafka数据清理机制(如何避免消息堆积)
Kafka中topic的数据都存储在分区上,分区如果文件过大会分段存储segment,每个分段都在磁盘上以索引和日志文件的形式存储,这样存储的好处一是方便管理二是方便清理。
清理日志一共有两个策略:一是根据消息的保留时间,时间到了直接清除;二是根据topic存储数据的大小,如果超出了topic的承受范围,那最早的在topic里的数据会被删除。
五.JVM
5.1 JVM运行时的数据区域都有什么(JVM结构)(JVM组成)(JVM运行流程)
5.2 Java堆的介绍,堆内存分配策略
5.3 什么是虚拟机栈
5.4 JVM中方法区
5.5 JVM中堆和栈的区别
5.6 类加载器是什么?有哪些?
5.7 什么是双亲委派?为什么采用双亲委派?
5.8 类装载的执行过程?(难度高考的少)
5.9 简述Java垃圾回收机制?(GC是什么?为什么要GC)
5.10 对象什么时候可以被垃圾器回收
5.11 JVM 垃圾回收算法有哪些?
5.12 说一下 JVM 有哪些垃圾回收器?
5.13 详细聊一下G1垃圾回收器?
5.14 强引用、软引用、弱引用、虚引用的区别?
5.15 JVM 调优的参数可以在哪里设置参数值?
5.16 JVM 调优的参数都有哪些?
5.17 CPU飙高排查方案与思路?
六.多线程
6.1 线程和进程的定义
当一个程序被运行,从磁盘加载这个程序的代码至内存,这时就开启了一个进程。
一个进程之内可以分为一到多个线程。
一个线程就是一个指令流,将指令流中的一条条指令以一定的顺序交给 CPU 执行
线程是最小的调度单位 进城是资源分配的最小单位,在Windows中进程只作为线程的容器,本身不活动。
6.2 线程与进程的区别
线程是最小的调度单位 进城是资源分配的最小单位.
Windows中进程只作为线程的容器,本身不活动。
6.3 如何创建一个线程?(线程的创建方法)
6.4 创建线程时,runnable和callable有什么区别?
6.5 线程的状态有哪些?它们的状态是如何变化的?
6.6 怎么停止一个线程?这两个方法的区别是什么?
6.7 如何唤醒一个线程?两种唤醒线程方法的区别是什么?
6.8 如何开启一个线程?两种开启线程方法的区别是什么?
6.9 Synchronized(对象锁)的底层原理是什么?(顺便讲一下锁升级机制)
6.10 讲一下CAS?
6.11 讲一下乐观锁和悲观锁?
6.12 什么是volatile?
6.13 聊一下ConcurrentHashMap
6.14 线程池是什么?(线程池怎么创建)
6.15 线程池的种类都有哪些?
6.16 创建线程池时,线程池的核心参数都有哪些?
6.17 如何确定线程池的核心线程数?
6.18 为什么不建议用Executors创建线程池?
6.19 谈谈你对ThreadLocal的理解
七.SSM
7.1 MyBatis的执行流程
读取MyBatis配置文件:mybatis-config.xml加载运行环境和映射文件->构造会话工厂SqlSessionFactory->会话工厂创建SqlSession对象->操作数据库的接口,Executor执行器->Executor接口的执行方法中有一个MappedStatement类型的参数,封装了映射信息->输入参数映射->输出结果映射
7.2 Mybatis的延迟加载(底层原理)
7.3 Mybatis的一级、二级缓存
7.4 Spring框架中的单例bean是线程安全的吗?
7.5 Sping 什么是AOP,项目中AOP的作用?
7.6 Spring中事务失效的场景有哪些
7.7 Spring的bean的生命周期
7.8 Spring中的循环引用问题
7.9 SpringMVC的执行流程
7.10 SpringBoot的自动配置原理
八.网络原理
8.1 OSI 的七层模型分别是?各自的功能是什么?
8.2 为什么需要三次握手?两次不行?
8.3 为什么要四次挥手?三次不行?
九.设计模式
9.1 什么是工厂模式?
9.2 什么是责任链模式?
9.3 常用的设计模式都有哪些?
十.Linux
10.1 Linux的基本命令?
10.2 Linux中创建及查看文件的方式
10.3 linux中的查看进程命令
10.4 Linux中文件的权限怎么查看和更改
十一.集合
11.1 Arraylist底层的实现原理
ArrayList底层是用动态的数组实现的,ArrayList的初始容量为0,只有第一次扩容时才会变为10,ArrayList在进行扩容的