面经分享--招银云创汇总
一、Java线程池核心参数,拒绝策略怎么选择,实际用的哪种
1.核心线程数,最大线程数,非核心线程数的空闲时间,空闲时间单位,阻塞队列,工厂模式,拒绝策略。
拒绝策略有
1.直接抛出异常,由程序员自行处理
2.由提交任务的主线程亲自来做任务,阻塞了任务的提交,间接起到 “限流” 作用,避免任务队列无限制膨胀。
3.丢弃掉队列中最旧的任务
4.丢弃被拒绝的任务
实际用的是第二种,也就是为了保证任何一个任务都不被丢弃,而使用的由主线程亲自来执行任务,从而阻塞任务的提交
二、HashMap的结构,如何保证查询的效率是O(1)
HashMap之前是数组+链表,JDK1.8之后就升级成了数组+链表+红黑树,这个升级就是为了当元素过多的时候,链表太长了,导致查询的时间复杂度变为O(n),升级之后当链表的长度超过8的时候,就自动升级为红黑树,让查询的时间复杂度变为O(logn)。
如何保证查询效率:1.优质的哈希函数:减少哈希冲突
2.合理的数组容量和扩容机制
3.哈希冲突的高效处理
三、Mysql建立索引的原则
1.为高频查询,少量修改的字段建立索引
2.给区分度明显较高的字段增加索引
3.建立联合索引的时候,将区分度高的字段放在左侧,避免重复索引
4.避开索引失效的场景:聚合函数,使用了不等于,模糊匹配,隐式转换
5.特殊情况:避免对null值较多的字段建立索引
四、Redis持久化的策略
Redis采用了RDB和AOF两种方式进行持久化:
RDB就是生产快照的方式(二进制文件),可以手动执行也可以自动执行,单一二进制文件,体积小,加载速度快。bgsave 采用子进程写入,主进程几乎无阻塞(仅 fork 瞬间可能有短暂阻塞)。
AOF记录所有写操作命令,每执行一条命令,Redis会将命令追加到AOF缓冲区中,再根据appendfsync 策略同步到磁盘。比较追求实时性
Redis主要是采用RDB+AOF的方式进行数据的持久化,既能保证快速恢复,在恢复这段时间所产生的数据,也能通过AOF的机制将这部分数据恢复
五、https加密原理
https运用了对称加密和非对称加密两种加密方式,客户端访问一个服务器,服务器会返回一个证书,这个证书是可靠机构颁发的,客户端的操作系统就会去判断这个证书是否合法,是否是目标服务器的证书,之后客户端把对称加密的密钥通过服务器的公钥进行加密,之后服务器拿着公钥的私钥对公钥进行解密,然后获得对称加密的密钥,之后双方正常通过这个密钥进行数据传输
六、sleep和wait的区别
sleep是Thread的一个方法,强制线程去休眠一段时间,之后自然唤醒,而sleep是Object的一个方法,调用了之后,会释放锁,然后由其他线程进行唤醒,主要区别就是是否释放锁
七、TCP和UDP的区别
两者都是传输层的协议,TCP需要双方进行连接,而UDP不需要,同时TCP是基于字节流进行数据传输,而UDP基于数据报的形式,同时TCP有一些机制如确认应答,超时重传,滑动窗口等来保证传输数据的可靠,而UDP没有这些机制,所以TCP在传输的实时性上弱于UDP,UDP主要用于追求实时性的场景如视频通话等
八、Spring事务失效的场景
1.自调用,在方法内部通过this来调用,this指向的是实例,而事务的使用是通过代理对象,导致了事务的失效
2.方法不是public修饰,这是由于spring自身实现的时候的规定
3.事务方法所在类未被spring管理
4.异常被捕获,未抛出,Spring 事务默认只在未被捕获的 unchecked 异常(继承 RuntimeException)或 Error 发生时,才会触发回滚。若事务方法中手动捕获了异常且未重新抛出,则 Spring 无法感知异常,事务不会回滚。
5.抛出的异常与指定回滚的异常不匹配
6.事务传播机制行为设置不当
九、Spring依赖注入的原理
依赖注入ioc是spring的一个核心,主要是将对象的创建使用交给spring容器进行管理,我们之后使用对象不用再去new了,而是直接从spring中进行获取。原理就是通过Bean的定义,通过beandefiniton标识出哪些要由spring进行管理,之后生成一张注册表进行记录,之后是bean的实例化,依赖注入,再到bean的初始化,bean初始化的时候就会去调用beanpostprocessor进行前置处理,之后调用aware接口将所有内容注入之后,再进行后置处理,主要是通过反射来获取一些类的属性和方法
十、Java创建对象有哪些方式
1.new
2.反射
3.序列化
4.clone()
十一、什么时候添加一个Java对象会失败
1.内存不足
2.类信息异常导致创建失败:1.类未找到,类加载失败
十二、自定义注解需要注意什么
1.注解interface声明:用 @interface 替代 class/interface,定义注解名称。
2.添加元注解:修饰注解本身,指定注解的作用范围、保留策略等。
3.注解中定义的 “成员变量”,用于携带信息(类似方法声明,无方法体)。
十三、抽象类和接口的区别,分别在什么时候适合使用
抽象类主要是体现is-a关系,接口主要是has-a关系,只能单继承,可以实现多个接口,抽象类偏向于如何做好,接口偏向于怎么做。
抽象类:提取共性,定义基础行为:一个公共交通抽象类,有共同的属性(名称、速度)和基础行为(启动、停止),,但 “行驶” 方式不同(汽车在路上跑,轮船在水里游),因此用抽象类定义共性,抽象方法留给子类实现。
接口:定义扩展功能(能力契约):部分交通工具具有 “载人” 或 “载货” 功能,但不是所有交通工具都需要(如自行车可载人,货车可载货,轮船两者皆可)。用接口定义这些 “能力”,让需要的类实现。
十四、JVM的内存划分
1.程序计数器:线程私有的,最小的一块区域,记录下一条指令执行的地址
2.虚拟机栈:私有的,与方法的使用有关,当方法执行的时候,会开辟一个栈帧,里面会记录一些参数信息,返回地址,动态链接等,然后在操作数栈对这些参数进行一系列的操作,之后返回,方法执行结束后这个栈帧也就消失了
3.本地方法栈:与虚拟机栈类似,但更多的是记录一下“NATIVE”方法,也就是JVM底层的一些方法实现
4.堆:公有的,最大的一块区域,主要是存储一些对象和变量,分为新生代和老年代,新生代里面又分为eden区,s0,s1区,垃圾回收主要场所就是在堆中
5.方法区:字符串常量池,一些静态变量,和常量的存储
十五、什么时候会出现StackOverflow Error
StackOverflowError 是 Java 虚拟机(JVM)在方法调用栈(虚拟机 stack)溢出时抛出的错误,通常由无限方法递归调用过深或栈内存空间不足导致。
Java 中,每个方法调用会在栈中创建一个栈帧(Stack Frame),用于存储局部变量、方法参数、返回地址等信息。当方法执行结束,栈帧会被弹出栈。若方法调用层级过深(如无限递归),栈帧会不断累积,最终超出 JVM 分配的栈内存容量,导致 StackOverflowError。
