蚂蚁金服-全球跨境支付-Java技术一面review
自我介绍:学校经历 + 公司经历(需要时间加长)
pop项目介绍
项目的难点:架构设计 表结构 模块划分(1. 基础模块:物料信息 档期信息 印厂信息 2. 业务模块:设计 审核)
流程梳理(1. 需求来源多:日配非日配 2. 角色较多:md中台设计部法务品管公关印厂门店运营)
设计:pop系统作为需求的收集方,对外提供dubbo
后续优化:
1. 复用原有业务流(蜂利器工作流),把前pop系统作为流程节点处理的操作系统
2. 做一些业务开关,不同的需求有各自的配置,灵活性(成本高)
多线程安全的三大特性:原子性、可见性和有序性
Object类中的方法:wait,notify,notifyAll 必须在synchronized(obj){……}中调用
wait后重新获得锁才能继续执行 同步代码块结束后才会释放锁 等待唤醒机制;
volatile:轻量级锁 原理:主内存 本地内存
每个线程执行时,先把变量从内存读到线程自己的本地内存中对其操作,操作完成后在某个时间刷新主内存。
加上volatile修饰之后,将缓存的数据写会主内存;使得其它线程缓存失效。
底层实现:赋值时加lock指令 会锁住总线 阻塞其它线程获取变量 且使得其它线程缓存失效!
为什么每个线程维护一个变量的缓存:解决CPU运算速度与内存读写速度不匹配。
sync:在编译的字节码中加入了monitorenter和monitorexit这两个指令。
monitorenter指令会获取锁对象,如果获取到了锁对象,就将锁计数器加1,未获取到则会阻塞当前线程。
monitorexit指令会释放锁对象,同时将锁计数器减1。
等待的线程是非公平调度
流程:获取锁失败进入锁池队列 -> 锁被持有的线程释放,幸运的一个线程被唤醒 -> 被唤醒的线程获得处理器 -> 获得锁 -> 执行同步代码。
1.6优化 锁的力度升级?
偏向锁 -> 轻量级锁 -> 重量级锁
偏向锁:优化了只有一个线程重复获取锁和释放锁的消耗;
轻量级锁:多个线程发生竞争时,通过CAS自旋操作来获取锁,极短时间重复尝试获取锁;
重量级锁:没办法了 直接阻塞
总结:volatile本质是在告诉jvm当前变量在寄存器中的值是不确定的,需要从主存中读取,
synchronized则是锁定当前变量,只有当前线程可以访问该变量,其他线程被阻塞住。
Lock:比sync更灵活,sync的缺点:一个线程获取锁 另一个线程只能等待下去
tryLock尝试获取锁 成功/不成功做其它事情
Lock是可以被中断的
ReentrantLock可重入读写锁实现了Lock接口,进入一个sync方法,再进一个 诶 就是皮~
可重入如何实现呐?
volatile int state 计数+1 再次进入时 这个线程与持有锁的线程是否是同一个线程
悲观锁:sync 直接给丫的锁住
乐观锁:CAS CompareAndSwap:区别于sync同步锁的一种乐观锁 ->
AtomicInteger用volatile保证int value可见性,JNI操作CPU的CAS指令
(多处理器时给cmpxchg指令加上lock前缀,确保对内存的读-改-写操作原子执行)
-> 优:高效解决原子操作 缺:ABA问题,循环时间长开销大,只能保证一个共享变量的原子操作
幂等性接口设计:
1. 场景是这样:库存系统定时给POP推送蜂特卖品,系统对外暴露dubbo接口,参数包括幂等性ID,这个字段设置成唯一索引,
接口实现为先查后插。情景举例:两个重复请求 —— B端的接口幂等设计
2. C端 高并发的场景设计 上述存在的问题:第二次请求会报唯一索引冲突
设计:Redis锁setNx 第一个请求获取锁插入数据 结果放到缓存里 第二次请求时 获取不到锁 就循环重试看缓存中有无结果。
线程池:
优势 :降低资源消耗 提高响应速度
参数:核心线程数(常驻线程数)、最大线程数、存活时间、阻塞队列(基于数组,基于链表)和拒绝策略(默认抛异常)
execute/submit提交任务
线程池的流程分析:
未达到核心线程数创建线程 达到将任务加入等待队列 队列已满新建非核心线程执行任务 队列满且达到最大线程数抛出异常
(看过源码 如何实现多线程复用的!poll从缓存中获取任务 无则返回null / take从缓存中获取任务 无则阻塞)
hashMap实现:链表+红黑树 6/10亿 存储获取原理 扩容机制(初始容量 加载因子 扩容增量)
hash函数(hash&length-1的好处 巧妙) 扩容会导致死循环
hashMap并发插入:1.扩容时rehash死循环 2.只插入成功一个元素
currentHashMap:分段锁,包含两个静态内部类MapEntry和Segment(继承了ReentrantLock),
前者用来封装映射表的键值对,后者用来充当锁的角色。
mysql :基础架构(连接 分析 优化 执行 分为server层和存储引擎层)
索引:为啥要用B+树 场景决定:等值查询 区间查询 插入 N≈1200
(主键索引中/聚簇索引:非叶子结点记录key值 叶子结点存储行记录 非聚簇索引叶子结点记录主键索引值)
回表 覆盖索引 最左前缀匹配 索引下推
事务特性:原子性 一致性 隔离性 持久性 隔离级别(读未提交 读提交 可重复读 串行化)
事务隔离的实现:MVCC 多版本并发控制 每次更新数据时会生成一个数据版本(事务ID 和回滚操作undo log)
数据版本具体指什么? 事务ID+回滚日志undo
可重复读隔离级别实现:MVCC+行锁 (查询:一致性读 和 更新:快照读)
面试官点评:
优点:追求技术+ACM+写博客
缺点:缺少对项目思考
个人总结:自己学了很多知识,却没有表达出来,也是因为自己边工作边面试的结果。
认清自己会的点 长处:数据结构和算法、多线程并发、MySQL、幂等性接口设计和开发流程理解
ps:最近每天白天项目发布 半夜自己准备面试 突然想到了自己刚毕业找工作的辛酸 哈哈哈哈哈
高谦虚同学说:如果老王能进支付宝 就嫁给他 哈哈哈哈哈