面试题2

一、自我介绍,自己会些什么?

  • 处理过高并发问题
  • 项目优化经验
  • 排查OOM故障
  • jvm,mysql,redis底层有着深入的了解
  • 项目负责人
  • 熟悉项目开发流程

二、什么是并发问题?

  • 多个线程同时操作一个公共变量,这个公共变量可以是java中的一个局部变量也可以是mysql中的一条数据,当a,b线程同时将数据加载到自己的工作内存中,a线程对自己工作内存中的数据进行操作修改,将数据更新到了缓存中,然而b线程这是不知道数据已经被更新,b线程也在原来的数据上做出了修改,也更新了回去,这时会把a线程更新的数据覆盖掉,这就是一个并发问题。

三、mysql的优化流程

  • 建立一个合适的索引,例如多个字段查询,可以简历一个联合索引,比如你只联合查询二个字段,如果这时你也要联查其他常用的字段,可以将这些字段放入这个联合索引中。
  • 代码上,for循环插入数据优化为mysql批量插入,效率值相差百倍
  • 添加缓存,减少数据的访问压力
  • 定期整理空间碎片,刚开始存储数据在磁盘中是顺序存放的,当频繁对数据库进行增删改时,这时就会产生磁盘碎片,mysql查询效率自然而然就会降低,数据乱序了
  • 当mysql数据量上来了,可以考虑主从复制,减少数据库读取的压力,
  • 当以上都不能解决问题,这时候需要进行分库分表,减少单表数据量过大问题

四、redis实现分布式锁

  • 为什么能用redis做分布式锁,因为redis操作指令的时候是基于单线程的,天然不存在并发问题,最初可用setnx来做分布式锁,加完锁后,如果服务宕机,锁没有释放掉,就需要加入锁的过期时间,让其要不是我们手动给他释放,要么就是自己超时释放。如果这个业务处理时间过长,业务没有来得及处理完,锁就过期了,那么也过存在并发问题,这样的话我们需要引入redission,因为redission里面有一个开门狗机制,会自动帮你轮询查看你的业务有没有处理完,会帮你的锁进行续签,这是redis实现分布式锁的一个演化过程。

五、实际的项目开发流程

  • 产品经理对业务整理出原型
  • 开会进行原型评审
  • 通过后后端进行技术选型
  • 通过后各个模块负责进行数据库设计
  • 接口定义,交付前端
  • 过程中可能出现Ui评审,用例评审,开发完成后,与前端进行联调,自测没问题,将代码部署到测试服务器
  • 测试根据业务,正向流程,逆向流程都没问题了,发布到预发布服务器中(本地内测环境)
  • 产品,ui进行最后业务需求等方面的测试,验收
  • 验收完,代码封板,请示领导提交上线
  • 项目完成后进行技术总结,复盘

六、synchorized锁升级的流程是什么?

  • 它的锁升级流程是单向的,不会出现降级现象,它的锁有四种状态:无锁,偏向锁,轻量级锁,重量级锁
  • 刚刚创建对象时它的锁是属于无锁的一个状态,当线程进入同步代码块时,它会通过CAS操作去给线程中mark word中的那个持有线程id修改成自己的线程id,如果这个CAS修改失败,说明有其他线程持有锁,当前是处于并发情况,这个时候我们会给它升级成轻量级锁,升级之后会继续进行自旋,自旋到规定数量之后,如果还不能获取到锁,这时候会把它升级到重量级锁。
  1. 偏向锁为什么需要升级为重量级锁?
  • 自旋过多会空耗cpu资源的,所以此时线程直接进入内核状态的话会节省cpu资源
  1. 为什么不直接从偏向锁升级为重量级锁?
  • 这个时候线程会直接进入内核态,如果说锁竞争不是很激烈的情况下,它会增加线程上下文的切换,通过自旋可以减少上下文的切换,通过自旋可以马上得到锁的时候,就可以不用进行线程上下文切换,这样可以提高整体的一个效率。
  1. 重量级锁是怎么实现的?
  • 它依赖于一个monitor object对象,就是说当锁升级为重量级锁的时候它会直接关联这个monitor object对象,对象里面有三个核心参数:owner(作用:记录当前锁的线程),waitset(作用:当我们调用线程时,会把线程的节点放入这个waitset方法中),entryList(是一个有序列表,所有线程放在这个里面排队,先进先出,当我们去调用notified()方法的时候,会将waitset里面的一个节点放入entryList的尾部,当我们调用notifyAll()方法时,会将waitset中的所有节点放入到entryList的尾部)。
posted @ 2024-04-20 23:10  牛奶配苦瓜  阅读(5)  评论(0)    收藏  举报