这篇文章记录我的面经—北京小厂
介绍下你吧
代码语言:javascript复制从大一下学期开始学java,自己从网上找项目做,一周深挖一个方面的知识,广度方面-分布式这些都有了解
深度方面都有一些基础吧,就是这些。
是不是简历上的在线教育平台啊?是你一个人做的还是
代码语言:javascript复制这是一个学长的公司带我一块儿做的 然后没工资,我只是帮忙(笑着说嘿嘿)去学习
在里面都做了什么
代码语言:javascript复制比如下单,用rabbit搭建延迟消息这些搭建和设计,他们带我一起学习,有些东西是我去实现的,
一起完善这些落地的东西。
你在项目中解决哪些有代表性的问题?
代码语言:javascript复制您是说是比较难的还是些小bug
都可以,你感觉有代表性的,咱们可以聊一聊,
就是下单的时候,不是要往task表插入记录嘛,然后需要通过token去实现放重提交对吧
然后他是通过分布式锁来完成存在删除,保证它多线程下的原子性,但是他这样放重提交,
不能保证有些恶意用户,恶意竞争的商家通过轮询的方式,点一次获取,获取一次,虽然
库存会过一段时间,比如半个小时会释放,但是他这样恶意刷的话,比如100个库存,1个人全部刷完
这种问题,对吧,这里解决当时也是想了好久(笑的很大声)
有两种策略,一个是限流策略,比如一个用户一分钟只能下一次单这种
第二个就是redis预扣减,当然这里的话,因为是之前的项目,现在才想到这样解决
就是redis预扣减,先在redis预扣减,等支付再进行扣减,就不会有恶意扣库存的问题了
这是我感觉最近学习最深入的
预扣减和实际去扣减去扣减,怎么去同步?
代码语言:javascript复制这里我还没深入,是我学习的另一个项目,还没落地到这里,就是知道预扣减的好处
=========================================================
这里一直拖 被八股托太久了 马上就去复盘明白这个redis预扣减
平时在java中,数组和链表如何取舍的?
代码语言:javascript复制增加和删除用链表,改查用数组
因为链表是一个连一个的所以用链表,增加和删除会快一点
为啥修改和查看用数组
因为如果要删除一个数组的话,比如我要把那个2删掉,我要把后面的元素整体的移动一下
然后改查的话,数组遍历每一个下标 ,他是O(1级别的,而链表的话需要一个一个遍历
=============================================================
这里我又了解到,甚至是linkedList的作者都不会去使用链表,
因为即使他增加删除快一点,但是他增加删除需要先找到吧,这是对比数组的常数操作,O(1)是很浪费时间的
有没有办法,提高链表的查询速度?
代码语言:javascript复制双向链表吧,这样可能会快一点
面试官:那也是,你双向,一个从头一个从尾部,实际没改变
这里没了解过
============================================================================
这里真的傻了 好气 不过吃一堑长一智 下次知道就行了
有一个我学过 就是给链表加索引 也就是redis中用的跳表 用二分的思想,但是前提要保证链表有序
LRU问题,在链表的基础上加一个hashmap
这里推荐这篇文章
[]: https://blog.csdn.net/qq_46489085/article/details/124933345
我们如何比较字符串是否相等呢?
代码语言:javascript复制用equals
为什么不用其他的
等于比较的是地址,equlas比较的是堆里的内容
我们平时也会用到,加入程序里要实现乐观锁,你会怎么做?
代码语言:javascript复制乐观锁,用一个标识a,另一个我们并发访问的时候可以和他比较,一个线程不符合的话会直接失败
然后就是通过version解决乐观锁的ABA问题,
乐观锁我没在java里实现过,是在超发那里用的乐观锁
直接用的库存大于0这种,这样的乐观锁,这样的粒度比加版本号的小一点
乐观锁的本质,通过自旋和比较,怎么说,通过 emm,默认是没有竞争,假设没竞争这样去做
面试官:在数据库里面加乐观锁吗?
在sql,扣减嘛 update stock = stock-1 然后stock>0
===============================================================================
乐观锁在java中常用的cas(compare and swap)顾名思义先比较再替换,
(这里我列几个概念,大家自习了解,也是我之前混淆的,JUCCASAQS,CAS是AQS的基础,AQS是JUC的基础,
所以可以说CAS也是JUC的基础,CAS是非阻塞的算法,synchronized是阻塞的算法,需要注意的是juc可以实现乐观锁和悲观锁)
我们可以利用juc提供的原子类去在程序中实现乐观锁,(Atomicxx类和其中的方法如compareAndSet都是基于CAS算法实现的
(juc包括原子类、工具类和一些接口)Lock接口和他的实现类可以
实现悲观锁(ReentranLock
还有一点需要说明:CAS主要干两件事:锁自旋和乐观锁
所以可以这样回答:java中,可以使用juc提供的原子类和方法实现cas算法,从而实现乐观锁
(也可以把AtomicLong换成普通的Long,但是就必须手动实现一个cas自增的算法了)
如下面例子:
public class User {
private Long id;
private String name;
private Integer age;
private AtomicLong version;
// getter 和 setter 方法省略
// 更新 User 数据
public void update(User newData) {
// 读取数据库中的原始数据
User oldData = userDao.getById(newData.getId());
// 判断版本号是否相等
if (oldData.getVersion().get() != newData.getVersion().get()) {
throw new OptimisticLockException("数据被其他线程修改");
}
// 更新数据并增加版本号
newData.getVersion().incrementAndGet();
userDao.update(newData);
}
}
这里再拓展一下:
用时间戳实现乐观锁并不需要原子类,因为时间戳一般都是通过对当前时间的获取来实现的,而对
时间的获取是线程安全的。
以 User 示例为例,如果我们使用时间戳来实现乐观锁,可以将版本号 version 改为 timestamp
时间戳(毫秒数),然后在每次更新数据时,先从数据库读取旧数据,判断旧数据的 timestamp 是否
等于当前 timestamp,若等于则进行更新操作,否则抛出乐观锁异常。这种实现方式不需要手动实现
CAS 算法,也不需要使用原子类,代码比较简单:
public class User {
private Long id;
private String name;
private Integer age;
private long timestamp;
// getter 和 setter 方法省略
// 更新 User 数据
public void update(User newData) {
// 读取数据库中的原始数据
User oldData = userDao.getById(newData.getId());
// 判断时间戳是否相等
if (oldData.getTimestamp() != newData.getTimestamp()) {
throw new OptimisticLockException("数据被其他线程修改");
}
// 更新时间戳并保存到数据库
newData.setTimestamp(System.currentTimeMillis());
userDao.update(newData);
}
}
总结:
面试如果可以这样说,一种是通过版本号比较,利用juc提供的原子类和方法,实现cas算法,从而实现乐观锁,
还有一种就是基于时间戳,时间戳的获取没用并发安全问题,可以不借助原子类,
想深入学习乐观锁的伙伴可以看这篇文章
[]: http://www.manongjc.com/detail/61-jnkzpokxmwhpxul.html
那你对0拷贝做过了解吗
代码语言:javascript复制这里看过,但是每记录嘿嘿,当时先把深拷贝和浅拷贝学习了下,然后直接去忘记深入这个了嘿嘿
=====================================================
这里是操作系统方面的知识,
通过各种方式,在特殊情况下,减少数据的拷贝次数或者说减少cpu参与数据拷贝的次数。
我们用多线程,生产者消费者这种场景的话,平时怎么去做的
代码语言:javascript复制生产中,我知道的是线程池,不可以去Executors工具类去做,
生产中要自定义,用ThreadPoolExector
这里的阻塞队列要区分C端和B端,如果C端高并发请求下,
他的阻塞队列不可以太长,会有消息的堆积
B端的话要求,不要那么强的实时性,可以让阻塞的队列长一点
然后核心线程数要分io密集型还是cpu密集型,cpu密集型的话可以和cpu核数一致或者加1
io密集型,对cpu没那么高的要求,可以2N 1
然后ThreadPoolExector实现的话主要是核心线程数,最大线程数,拒绝策略,阻塞队列长度
当然拒绝策略使用默认的那个就行
然后这就是我知道的生产消费模型
用这个到项目上面,堆内存怎么配?
代码语言:javascript复制您能说的 精确点吗
就是线程池,我们使用的时候,会设计jvm的配置,这里的话会怎么去考虑?
这里的话,线程池的底层是一个hashSet,emmm,这里不会
面试官:比如,线程栈,默认的线程栈的大小,
没去了解过这里...
====================
这里我觉得面试官问的有点问题,jvm调优,应该告诉我一个确定的场景什么的
tcp连接熟吗
代码语言:javascript复制这个,他这个计算机网络,这里太多了 学习了 但是想不起来嘿嘿
太多了呜
面试:他有几次挥手啊
三次握手四次回收这样
面试官,假如说,挥手 的时候,有个状态叫closewait,这是什么原因产生的
emm忘记了呜
你是springboot熟还是alibabacloud熟吗
代码语言:javascript复制boot吧
面试官:拦截器这里怎么做,平时用过没?
拦截器,Intercepor,比如我用jwt实现登录的时候,就需要拦截请求,做出处理
这就是拦截器,我在这儿用的,
面试官:拦截器加载的顺序?
这里没了解
面试官:就是扩展一个接口,扩展一个类
(这里真蒙了,可能是有人进来了
我蒙了个,::就是实现一个类,重写Interpcptor方法,(这里我真是蒙的嘿嘿
我补了一句,主要是思想吗,api啥的记不住,用的时候看一下就可以了
===========================================================================
这里说的扩展一个类,就应该是我项目里的LoginInterceptor咋写的
我回顾了下,就是实现HandlerInterceptor接口,重写preHandle和postHandle,和afterCompletion方法
这是添加一个拦截器,
然后每个微服务要注册拦截器,这里需要实现WebMvcConfigurer
重写addInterceptors()方法,registry.addInterceptor去添加自己定义滴拦截器。
然后拦截器的加载顺序:
(下面的就是列举一下,我感觉没必要背会。。)
在 Spring Boot 中,拦截器是通过实现 HandlerInterceptor 接口来定义的。当请求过来时,Spring Boot 会使用一个拦截器链来依次对请求进行拦截和处理,拦截器的加载顺序是与它们在代码中注册的顺序相关的。
具体来说,在 Spring Boot 中,可以通过实现 WebMvcConfigurer 接口,并重写 addInterceptors 方法来注册拦截器。在该方法中,可以使用 addInterceptor 方法来注册拦截器,并使用 order 方法来指定拦截器的优先级。order 数值越小,优先级越高,即越先被调用。
默认情况下,Spring Boot 实现的拦截器链中包含以下几个拦截器(按照执行顺序排序):
ResourceUrlProviderExposingInterceptor
LocaleChangeInterceptor
ThemeChangeInterceptor
SecurityContextPersistenceFilter
HeaderWriterFilter
CsrfFilter
LogoutFilter
RequestCacheAwareFilter
SecurityContextHolderAwareRequestFilter
AnonymousAuthenticationFilter
SessionManagementFilter
ExceptionTranslationFilter
FilterSecurityInterceptor
如果我们在代码中什么都不做,那么这些默认的拦截器就会按照上述顺序被依次执行。如果我们需要自己定义拦截器,可以通过实现 HandlerInterceptor 接口,并在 WebMvcConfigurer 中的 addInterceptors 方法中添加我们自己的拦截器并指定其 order 值,从而改变拦截器执行的顺序。
面向对象里面有重载,对一个方法重载怎么实现
代码语言:javascript复制就是把形式参数改一下就是重载
大概情况我们就了解这么多,对我们公司有想知道的吗
代码语言:javascript复制公司的规模大概多大
面试官:我们公司有差不多400号人
我:属于小中厂是吗
面试官:小厂是吗
你在哪个地方
代码语言:javascript复制吉林
面试官:我们的公司在北京,有什么影响吗
我:大三也没啥课
准备暑期之后,上课的话也可以找人代课吗,实习挺重要的
面试官:所以可以在北京一直呆着是吗
对