1>请简述HashMap的put方法执行的流程
1)计算key的hashCode的值(异或运算)
2)如果散列表为空,就用resize()初始化散列表
3)如果没有发生碰撞,元素直接加入到散列表中
4)如果发生了碰撞,即hashCode值相同,就要分三种情况去判断
>>若key地址相同或者equals后的内容一样 则替换旧值
>>若是红黑树结构,调用树的插入方法
>>链表结构,遍历到某个空节点,尾插法进行插入,插入之后判断链表个数是否到达变成红黑树的阈值8
5)如果大于阈值,则resize()进行扩容
2>HashMap的数组长度为什么需要是2的幂次方
HashMap默认初始化长度是16 并且每次自动扩展或者是手动初始化容量时,必须是2的幂次方
1)为了数据均匀分布,减少哈希碰撞
2)输入数据若不是2的幂 HashMap通过一通位移运算和或运算得到的肯定是2的幂次数,并且是离那个数最近的数字
3>HashMap在什么情况下会进行数组扩容
超过负载因子定义(0.75)的容量,即16*0.75=12 就会扩大原数组大小的2倍,为32
4>下面这种情况 HashMap扩容几次
HashMap map= new HashMap(10000);
for (int i=0;i<10001;i++){
map.put(i,UUID.randomUUID().toString());
}
2的13次方<10000<2的14次方
底层会设置离10000最近的2的幂次方的容量,即2的14次方16384
所以当开始遍历时,只要不超过16384*0.75=12288,就不会触动扩容
所以上面是没有扩容的
5>解释volidate中线程可见性是什么
线程安全的三大核心就是原子性、可见性和顺序性,volidate实现线程安全的可见性
是java中用来保证并发访问同一状态的可见性的一种工具.可见性是指一个线程对内存中某一个地址的值修改必定能对其他访问该地址的线程生效.
6>MQ的事务消息是怎么实现的
1)发送事务消息(消息是属于半消息,对消费者是不可见的)-->同步发送
2)保存之后再通知生产者(消息中间件收到消息之后 会回调生产者的本地事务方法)
3)本地事务方法需要返回业务执行结果给消息中间件
4)发送本地事务执行结果(决定半消息如何处理)
5)收到生产者的本地事务的执行结果
- 如果是COMMIT 把半消息变成完整消息 对消费者可见
- 如果是ROLLBACK 就把半消息删除掉
6)如果半消息在消息中间件一定时间中一直没被处理,就会调用生产者的回调方法(回查机制)
-->根据消息查询本地事务的执行结果 给消息中间件返回本地事务的执行结果(第五步)
会累积发送16次 每分钟一次
7>支付过程中如何保证支付参数不被篡改
采用非对称加密
>>应用程序端
1)应用需要对参数进行加密 将参数封装成JSON字符串 使用应用私钥进行加密 得到密文(签名) 签名随着参数一并提交给支付宝
2)接收支付宝的回调 对签名进行解密操作 和明文进行对比 这个过程叫验签
>>支付宝端
1)接收参数 使用应用在支付宝配置的应用公钥 对签名进行解密的操作 然后和传过来的明文参数进行比对 ,验签过程
- 如果一致 说明过程没有篡改
- 如果不一致,过程被篡改
2)支付宝在验签完成以后 会回调应用地址 需要传递参数 使用支付宝的私钥进行加密 得到密文(签名) 随着明文参数一并发送
8>项目中的幂等性是怎么实现的
(节选幂等性如何实现?带你了解一波!!!_不才陈某的博客-CSDN博客)
幂等性-->一次请求和多次请求同一个资源产生相同的副作用
在系统高并发的环境下,很有可能因为网络,阻塞等等问题导致客户端或者调用方并不能及时的收到服务端的反馈甚至是调用超时的问题。总之,就是请求方调用了你的服务,但是没有收到任何的信息,完全懵逼的状态.
三种方式-->
1)状态机
很多业务中多有多个状态,比如订单的状态有提交、待支付、已支付、取消、退款等等状态。后端可以根据不同的状态去保证幂等性,比如在退款的时候,一定要保证这笔订单是已支付的状态
2)流水表
在往数据库中插入数据的时候,利用数据库唯一索引特性,保证数据唯一。比如订单的流水号,也可以是多个字段的组合。
3)token机制
针对客户端连续点击或者调用方的超时重试等情况,例如提交订单,此种操作就可以用Token的机制实现防止重复提交
9>支付宝付款了但是订单的状态没有变化
没有遇到这样的情况,因为支付宝有回调机制,在25小时内有8次回调,回调逻辑有问题,我们会提供人工手段 通过调用交易查询接口,客服确认交易状态,人工补单
10>简述分布式事务出现的场景 如何解决分布式事务
分布式事务是指事务参与者,支持事务的服务器,资源服务器及事务管理器分别位于分布式系统的不同节点上
1)单体系统访问多个数据库实例
如订单创建成功,库存扣减失败,就可能会导致”超卖”问题,这就是分布式事务出现的场景
2)多个微服务访问同一个数据库
如订单微服务和库存微服务访问同一个数据库
3)多个微服务访问多个数据库
如多个服务需要调用一个数据库实例完成数据的增删改操作
解决-->
1)全局事务(基本不用)
2)消息中间件(存在局限性)
3)TCC
4)Seata(常用)