面试题集合(一)

线程池

Java自带的线程池有几种?任务队列使用的是什么队列?

一共有四种,分别是:
1、newSingleThreadExecutor,单线程线程池,只有一个线程执行所有任务,如果这个线程异常结束,那么会创建一个新的线程来代替它。这种线程池确保了任务是顺序执行,且保证一定有线程去执行任务。
2、newFixedThreadPool,固定大小的线程池,创建一定数量的线程来执行任务,线程池中的线程数是固定不变的。
3、newCachedThreadPool,可缓存的线程池,线程数量是不固定的,当任务数量大于当前线程数时,会创建更多的线程来执行任务,同时也会回收空闲线程(60秒没执行任务的线程),这种线程池的线程数是没有上限的,依赖于JVM可创建的最大线程数(2的29次方-1)。
4、newScheduledThreadPool,可执行定时和周期性任务,线程数量也是无上限的。

任务队列:newSingleThreadExecutor和newFixedThreadPool使用的是LinkedBlockingQueue<Runnable>()队列,这个队列有一个特点:它是无界的,也就是说它可以无限添加任务,直到把你的内存耗尽,这点是需要注意的;newCachedThreadPool使用的是SynchronousQueue<Runnable>()队列,是无缓冲等待队列,它不存储任务,直接把任务交给消费者,必须等队列中的任务被执行后才能再添加任务。
还有一个有界的等待队列也常在线程池中使用,ArrayBlockingQueue<Runnable>()
具体参考:这里

线程池的各个参数,工作过程,是否有手动实现过线程池?

1、线程池参数,一共七个:
corePoolSize 核心线程数量
maximumPoolSize 最大线程数量
keepAliveTime 空闲线程存活时长
unit 空闲线程存活时长时间单位
workQueue 任务等待队列(ArrayBlockingQueue<Runnable>(),有序阻塞队列,FIFO排序)
threadFactory 线程工厂
handler 拒绝策略(AbortPolicy,直接丢弃任务,并抛出RejectedExecutionException异常)

2、工作过程:
a、线程池启动时会创建corePoolSize数量的线程;
b、当当前任务大于corePoolSize数量时,会将多余的任务添加到workQueue任务等待队列中;
c、当任务等待队列被塞满了之后,线程池会继续创建线程来处理任务,直到线程数达到maximumPoolSize数量;
d、这时如果还有任务过来,就会执行拒绝策略;
e、当任务被执行完之后,空闲时间达到unit且当前线程数大于corePoolSize数量,线程就会被回收。

3、手动实现现阶段还没有,希望后续会补上。

当线程池中的keepAliveTime设置为0,会怎么样?

非核心线程在空闲时会被立即销毁,另外keepAliveTime不能设置小于0的值,在构造方法里会抛出异常。
在这里插入图片描述

Java基础

HashMap的碰撞扩容过程

1、基本数据结构
HashMap基本数据结构由数组和链表组成,Java8引入了红黑树。HashMap的主链是一个数组,当元素发生碰撞时,采用的是链地址法解决方案,就是在发生碰撞的地址上引申出一条链表来存放发生碰撞的元素,在Java8之后,当链表长度达到8时,会转换成红黑树。
2、扩容
HashMap有两个属性:threshold阈值和loadFactor负载因子,threshold = 数组长度 * loadFactor,当当前Map中的元素大于阈值且发生碰撞时,就会产生扩容,扩容到当前容量的2倍,扩容主要是为了减少Hash碰撞。
举个例子:一个长度为16,负载因子为0.75的HashMap,至少在添加第13个元素的时候会发生扩容,至多会在添加第28个元素的时候发生碰撞

如何保证接口的幂等性

幂等性的含义就是同一个操作执行多次,产生的结果都是一样的,主要是为了避免接口重复调用导致数据错误的情况。
1、数据库唯一键
主要是为了解决重复添加数据的问题,当同一数据添加两次时,会因为违反唯一键约束而报错;
2、状态机
订单系统一般会有一个订单状态字段,比如未支付,已支付,代发货等等,这样我们可以在支付的时候,先查询一下订单的状态,如果是未支付的状态,才去真正支付,这样也很好地去避免了重复请求带来的麻烦;
3、全局唯一ID
比如消息队列重复消费问题,可以在消费消息的时候,创建一个全局唯一的ID存到Redis中,如果发生重复消费,先看下这个ID是否已经存在,如果存在的话,就说明该消息已经被消费了,直接给Broker返回ack;
4、版本号

如何获取线程执行的结果

有两种方式:
1、Future和Callable配合:
在这里插入图片描述
2、FutureTask和Callable配合:
在这里插入图片描述
需要注意的是:我们需要阻塞来获取线程结果,所以要根据自己的业务逻辑来调整代码,比如:可以先去做其他事情,等到需要线程结果的时候,再来阻塞获取线程结果。

数据库

索引失效的情况和索引未生效的情况

1、模糊查询,以通配符开头的模糊查询会导致索引失效;
2、在索引字段上做了任何操作,如函数、计算等;
3、使用不等于(!=、<>),会导致索引失效;
4、范围查询会导致索引右边的列不走索引,例如:a = 1 and b = 2 and c > 3 and d = 4,
如果创建(a, b, c, d)的联合索引,则d是用不到索引的,但是如果创建(a, b, d, c),则全都可以用到索引;
5、显式或隐式的类型转换或编码转换(字符集不同)都会导致索引失效;
6、数据量过少或者重复数据过多,会导致优化器放弃索引,直接全表扫描;
7、or条件,is not null会导致字段右边索引失效。

sql调优的过程和方法

1、排除缓存干扰:MySQL8.0版本之前是支持缓存的,8.0版本之后取消了缓存,原因是只要有更新操作,缓存就会全部清除,这就导致缓存起到的作用不大,并且还带来了存缓存的额外开销;
2、Explain,查看执行计划,看查询是否有用到最优索引;
3、避免回表,当使用非聚簇索引时,数据库实际上执行了两次查询操作,第一次先查询出符合条件的主键id,第二次根据主键id查询出需要的相关字段,第二次查询我们称之为回表,在我们实际使用中应该尽量避免回表操作来减少数据库查询次数。可以使用覆盖索引来减少回表,当索引上已经覆盖了需要查询的字段,就不会再去进行回表操作了。
4、change buffer,我们在做数据库更新操作的时候,操作并不会马上更新到数据库中,而且要看相关的数据页是否在内存中,如果数据页在内存中就会直接更新,但是如果数据页不在内存中,会在change buffer中先保存更新的操作,等到数据页被读到内存中再去执行更新操作,这样就减少了数据页从磁盘读取到内存的操作,提高了数据库的性能。将change buffer中的操作应用到原数据页中,得到最新结果的过程叫merge,系统有后台线程定期执行merge,关闭数据库之前也会执行merge操作,防止更新丢失。值得一提的是,唯一索引不会使用到change buffer,因为唯一索引要保证数据的唯一性,都要先将数据页读到内存中才能判断。
5、前缀索引,因为数据库的数据页是固定大小的(16K),也就是说,索引越长每个数据页可存的索引数量越少,索引过长会导致索引存储得过于分散,增加了查询的成本,所以如果索引字段前面的字段有较高的区分度的话,就可以使用前缀索引,减小索引长度,节省磁盘空间。

Redis

主从模式,主挂了,怎么办?

一主一从的模式只有主机具有写的权限,所以当主机挂了之后,redis就没有写入的功能了,我们可以先让从机充当主机,使用命令slaveof no one,暂时让从机拥有写的权限,然后再修复主机。主机修复之后,持久化从机的数据,生成dump.rdb文件,用从机的dump.rdb文件去替换主机的dump.rdb文件,做到数据同步,再重启主机,然后再恢复从机身份,执行slaveof 主机。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值