1.concurrenthashmap底层存储结构
ConcurrentHashMap1.8底层数据结构是数组+链表+红黑树。由CAS+Synchronized实现线程安全。代替1.7的分段锁segement
put原理:
允许协助扩容
2.threadLocal
线程本地变量,线程隔离。
线程中维护了ThreadLocalMap属性,它是ThreadLocal的内部类,key是ThreadLocal,它是弱引用。value是线程本地变量。
内存泄露问题
ThreadLocal被回收 && 线程复用(线程池)&& 没有调用set、remove、get方法
3. redis怎么使用的?
4.索引结构
索引:提高查询效率的数据结构
B+树
rocketMq事务消息底层逻辑就是通过在broker上创建和管理半消息,通过commit log 记录事务提交或回滚状态,保证消息的可靠性和事务最终一致性
事务消息相对普通消息最大特点:一阶段发送的消息对用户不可见,消费者不能直接消费。实现方法是:把消息的主题改成RMQ_SYS_TRANS_HALF_TOPIC,这样消费者没有订阅这个主题,就不会消费
半消息提交成功,就把消息放入目标(原)主题
7.如何设计一个延迟队列?
使用redis的zSet,用Zadd命令生产消息,key作为消息内容,score为时间戳,member为业务数据;使用zRangeByScore获取时间戳内的数据,轮询处理
8.分布式事务
9.一个接口3000qps,接口RT为200ms,预估需要几台机器?(每台机器为4核CPU)
首先,每秒需要处理的请求数(QPS)与请求响应时间(RT)可以计算出每台机器需要处理的并发请求数(CPS):
CPS = QPS * (RT / 1000) = 3000 * (200 / 1000) = 600
然后,我们需要计算每台机器的处理能力。由于每台机器为4核CPU,并且没有给出单个核心的处理能力,因此我们使用一个经验公式来估计每台机器的处理能力:
处理能力 = CPU核数 * 100
因此,每台机器的处理能力为 4 * 100 = 400。
最后,我们可以通过将每台机器的处理能力除以每台机器需要处理的并发请求数,来计算需要的机器数量:
机器数量 = (每秒请求数 / 每台机器处理能力) 向上取整
机器数量 = ceil(600 / 400) = 2
因此,预估需要2台机器来处理3000qps,接口RT为200ms的请求。
10.分布式id实现方式,如何解决时钟回退问题
11.redis expire底层实现
Redis 的 expire 命令用于为一个键设置过期时间,即在指定时间之后自动删除该键。底层实现原理是使用一个叫做过期字典(expires dict)的数据结构,其中每个键都映射到它的过期时间。
redis过期删除策略
12.redis setnx底层实现
Redis 的 SETNX 命令用于将一个键值对(key-value pair)设置到 Redis 中,但只有在该键不存在时才会进行设置。底层实现原理是使用了 Redis 的基础数据结构之一——字典(dictionary)。当调用 SETNX 命令时,Redis 会先检查要设置的键是否已经存在于字典中。
如果键不存在,则会将键值对添加到字典中,并返回 1 表示设置成功;否则不做任何操作,并返回 0 表示设置失败。
这个操作可以保证对于同一个键,SETNX 命令只会执行一次设置操作,避免了并发设置导致的竞争问题。
1.redis实现分布式锁
Redis 可以通过使用 SETNX(SET if Not eXists)命令和 EXPIRE 命令来实现分布式锁。具体步骤如下:
在 Redis 中创建一个键,作为锁标识。
使用 SETNX 命令尝试将锁标识设置到 Redis 中。如果 SETNX 返回 1,则表示成功获取锁;如果返回 0,则表示锁已经被其他客户端持有,获取锁失败。
如果成功获取锁,则可以使用 EXPIRE 命令为该键设置过期时间,以防止锁一直被某个客户端持有,导致其他客户端无法获取锁。
同时需要设置客户端唯一标识,防止被其他客户端误释放
执行业务代码逻辑。
释放锁时,需要使用 DEL 命令将锁标识从 Redis 中删除,让其他客户端可以继续获取锁。
需要注意的是,由于分布式环境中存在网络延迟、进程崩溃等异常情况,因此在使用分布式锁时需要特别关注死锁和重入问题,并采取相应的措施进行处理。例如,在 SETNX 命令执行失败后,可以加入重试机制,或者使用 Lua 脚本保证 SETNX 和 EXPIRE 命令的原子性操作
2.哪些产品用到多线程?
3.面对多个线程竞争资源,如何处理
4.用过哪些设计模式
5.单例模式,哪些场景用?为什么要用?
6.sql如何调优
7.项目中哪里用到MQ
8.谈谈你对Spring cloud的理解
9.有对redis做持久化吗?怎么用的
10.对linux有了解吗
1.乐观锁、悲观锁、共享锁、独占锁
2.说一说对微服务的理解
3.介绍微服务组件还有在项目中怎么用
4.排序算法
5.redis缓存穿透、击穿、雪崩
6.hashMap线程安全吗?想让他线程安全,要怎么解决?
7.写一个sql语句查询200W后的10条数据(深分页)
8.问项目业务上用技术怎么实现
1.JVM相关知识点
2.集合框架原理
3.微服务相关组件
4.缓存相关知识
5.个人项目经验,遇到的困难和挑战
1.mysql索引b+树节点存的是什么?
2.redis set、zSet的数据结构什么时候会使用哈希表
set的元素数量小于512时使用整数集合,否则使用hash;
zSet的元素数量小于128个,且每个元素大小小于64字节时,使用哈希;否则使用跳表,使用跳表目的是查询效率高
3.线程池参数能够运行时动态调整吗?
能。
可以将线程池的参数(核心线程数、最大线程数,阻塞队列长度)迁移到分布式配置中心上,实现线程池参数可配置和即时生效
1)为什么需要动态设置?
因为存在流量不均衡的情况
2)动态更新的工作原理
- setCorePoolSize
- 在运行期间线程池调用此方法修改核心线程的数量,线程池会直接覆盖原来的值
- 并且基于当前值和原始值的比较结果,采取不同策略
- 如果当前值小于工作线程数,证明有多余工作线程,此时会向多余线程发起中断请求,实现回收
- 当前值大于原始值且当前队列中有待执行任务,则线程池会创建新的worker线程执行队列任务
- setMaxmiunPoolSize
- 校验参数合法性
- 覆盖原来的值
- 判断工作线程是否大于最大线程数,是则对空闲线程发起中断请求
3)动态设置需要注意的点
获取任务时,当工作线程大于最大线程数,就会对工作线程数-1,并返回空,那么就没有获取到任务。一加一减线程,相当于失效;
解决:设置核心线程数的时候,同时设置最大线程数。
如果低峰期怎么办?当参数allowCoreThreadTimeOut设置为true时,空闲核心线程也会被回收。相当于线程池自动动态修改;
4)动态指定队列长度
LinkBlockingQueue的capacity是final修饰的。无法修改。那我们可以自己定义一个queue,可以修改capacity。
这道题涉及的线程池问题
1)线程池被创建后,就有线程吗?如果没有,可以对线程池进行预热吗?
线程池被创建后,没有任务时是没有线程的。预热有两个方法
- 全部启动:prestartAllCoreThreads()方法
- 仅启动一个:prestartCoreThread()方法
2)核心线程数会被回收吗需要什么设置?
默认是不能的。如果需要回收,则调用allowCoreThreadTimeOut(boolean value)