历经20多天搜集的各家大大小小的面试题
在这11月份,对于换工作不是一个明智选择,当然也不是绝对的,只要你技术过硬,还是可以的,我从11月3号开始找工作,找了整整20多天,因为我是菜鸟,但是在面试的过程中,我学到了很多东西,我认为不管一个人多牛逼,但还是有不足的地方,这些我们都可以在面试中发现自己欠缺的东西,及时的查缺补漏,这是最好的选择,所以我将自己整理的面试题分享给大家。
image.png
面试涉及到的知识点:
一、基础知识
一般是从Java基础到JavaEE吧,中间涉及到了前端js和一些前端框架如jquery、bootstrap、easyUI、Freemaker等,当然还有就是数据库的知识,在就是一些常见的框架如spring、springMVC、MyBatis、springboot、shiro等主流框架。
二、微服务和分布式:
在服务这一块,一般就是分布式和SOA架构,如:springClound、dubbo、zookeeper等rpc框架。可能中间会涉及到一些消息插件如:MQ、kafka等。
三、非关系型数据库
自己常用的就是redis,还有mongodb等。
四、版本管理工具
常见的有svn.现在大部分都在用git。
五、使用的开发工具
自己一直在使用IDEA、Eclipse、Maven、Linux、Ducker等。
六、常用的服务器
Tomcat、Resin、JBoss、WebSphere、WebLogic等,但别 的不是很了解,一直在用战斗机下的Tomcat服务器。
在这20多天的面试中,基本是围绕着这些大的知识点进行问题的询问,当然最重要的是简历上的项目介绍。接下来挨个来说问到的问题并简单的作答。
1.Java基础部分
(1).oop的特性:
我们都知道是封装、继承、多态。这里我简单说下我自己的说法:
封装:封装就是将一个对象的一些属性私有化,不对外暴露,也是为了数据的安全。
继承:继承就是子类继承了父类的某些共有的属性和方法,子类同样可以拥有属于自己的特性,只能比父类的范围大,这也是为了功能拓展吧。
多态:一个类在不同的场景下有不同的使用场景。就是父类的引用指向了子类。
(2).方法的重载和重写的区别
重载:重载体现在子类和父类之间,是一种多态的体现。
常见的规则:方法名相同参数列表不同,返回值类型可以相同也可以不同
重写:重写体现在同一个类中。
常见的规则:方法名和参数列表相同,返回值类型也要相同
(3).String类的常见api(这个自己去看看)
(4).final关键字的用法
我们知道final可以用来修饰一个类,如String类,用它来修饰表示该类是无法继承的。
同样也可以用来修饰我们在接口中定义的一些常量等,表示该常量是无法在进行修改的,可是有面试官问我final可以用来修饰方法?
答案是可以的,用它来修饰方法就表示该方法不能被覆盖或者重写,同样也可以修饰方法中的形参,用它来修饰方法中的参数表示该参数变量的值是无法改变的。
总之final在spring的框架源码中大量的用到,好处就是可以提高性能,还有就是jvm可以缓存它,由于它是不可变的,读写的性能特别好。
(5)String s = new String("xyz")时,创建了几个对象
答:创建了两个对象,这个问题是指明对Java内存机制的堆和栈有一定的了解,这里只针对问题来说,一个对象时String类的“xyz”,一个指向堆内存的引用s。
StringBuffer和 Stringbuilder的区别
这个问题很好答,对于StringBuffer而言是线程安全,Stringbuilder是非线程安全的,这也是我们在开发中用Stringbuilder的原因,还有就是两者的底层是char数组来扩容的。具体的感兴趣的可以去看看他们的源码
(5).集合中常用的有哪些,说出各自的特点?
ArrayList和Linkedlist、treeset、treeMap、hashMap、hashTable等,区别就不说了,感兴趣的自己去看一些,这里只说面试官问到我的问题和解答。
HashMap的底层
答:hashmap底层是数组+链表+红黑树构成的(jdk1.8的特性)
HashMap的put方法是如何存放数据的,(就是put的执行流程)
大致是这样的,我们知道haspmap是key-value的存储结构特性,在调用put方法时,它是这样执行存数据的过程的,底层是一个hash表,会调用一个hash(key)的算法,并得到一个hashcode的值,会根据这个值将数据存放到指定的hash表中,会涉及到碰撞过程。
还有就是我在保存一个值时,假如我的这个key是不存在的,会返回一个null的,hashmap中允许key可以为null。
有个面试官问我既然HashMap是线程不安全的,如何解决?
我们都知道hashmap是继hashTable之后为了解决效率的而出来的,也就是说hashtable是hashmap的前身,看过源码的会知道hashtable是线程安全,所以解决hashmap线程不安全问题可以用hashtable来实现,还有一个ConcurrentHashMap和Synchronized Map这两者都是线程安全。
在set集合中有序的是哪一个?
答:我们知道set集合特点是无序不重复特点,在其他的实现类中treeSet和treeMap确是有序的,两者区别是treeSet是有序不重复,treeMap是有序可重复的。
微信截图_20181124160234.png
微信截图_20181124160144.png
微信截图_20181124160603.png
Java基础部分常问到就是集合部分及底层的实现,这里还有就是ConcurrentHashMap和Synchronized Map这两个Map是解决并发问题中常用的单独说。
2.js中常见 的面试问题
111.png 1212.png(1).js中创建数组的常见方式
方式一:var array = new Array();表示创建一个空数组
方式二:var array = new Array(2);表示创建长度为2的null数组
方式三:var array = ["a","b"];
(2).js中常见的获取元素的方式有哪些?
1.通过元素的id来获取如:document.getElementById();
2.通过元素的name属性来获取:document.getElementsByName();
3.通过元素的tag标签来获取:document.getElementsByTagName();
常见的就这三种。
(3).js中的事件的书写方式:
1.事件的三要素:事件源(事件主体)、事件函数、响应处理等。
2.事件绑定的方式:
(1)在元素标签上使用onclick属性配置
(2)获取事件源 在函数调用的时候传递this
(3) 获取事件对象: 在函数调用的时候传递event
代码示例如:
上图为事件绑定的方式一。
方式2.png方式二:
在js代码中使用元素.使用 "元素.onclick=响应函数"进行事件监听
通过this获取到事件源,通过形式参数event获取到事件对象
代码如图所示:
fangshisan.png放式三:
自定义函数绑定
代码如图:
事件的绑定大致就三种,常用的比较多的是方式1和方式2
(4).js中用过哪些选择器(至少6中已上)自己去看看
(5)js中的闭包、定时器、还有jquery中的数组遍历的常见方式如fori、.map()等,
.map会返回一个新的数组,这是区别。
(6).ajax的原理
答:ajax的原理实质是xmlHttpRequest类,基本上说了这个类面试官一般不会往下问了。
(7).如何防止Ajax重复提交表单
答:在$.ajax请求中的beforeSend方法中把提交按钮禁用掉,等到Ajax请求执行完毕,在恢复按钮的可用状态。
(8).ContentType和DataType的作用?
答:ContentType:意思是告诉服务器我发的数据类型,而DataType是前台往后台传数据的格式,如json、html、text等。
三、数据库常见的面试问题
对于数据库来说,是面试必问的东西,一般面试官会问,做过sql优化、分库、分表等操作,关于分库、和分表来说一般是结合项目来说的,我这里简单的说一下问到我的问题。
1.常见的SQL优化方式有哪些?
答:(1).最直接有效的是我们可以通过redis加缓存,其目的减少与数据库的交互从而来达到我们的目的。
(2).我们可以配置数据库的主从,和读写分离
(3).在查询频繁的字段上我们可以加索引(索引不是越多越好)
(4).在使用子查询时,不要将复杂的子查询作为where后面的条件
(5).将排序的操作可以在索引中来完成
(6).永远是小结果集驱动大结果集
简单的就说这一些,有的面试官会结合实际的情况具体询问。
2.MySQL的引擎有哪些,各自的区别?
(1).mysql实际有三种引擎,但我们常用的是Innodb和MyIsAM两种。
两者区别:
INoDB支持行级锁,而MyIsAM是表级(两者的粒度不一样)
INoDB是事务安全的,而MyIsAM是事务不安全的
INoDB不支持全文检索,而MyIsAM支持
INoDB支持外键,而MyIsAM不支持
这是两者 的区别,简单的了解一下,具体的里面的东西我不是很清楚,感兴趣的自己可以去详细的了解下
3.记得有一个面试官问我,如何配置MySQL的事务和防止数据库的脏读?
我是这样回答的,因为MySQL中的引擎,只有是INoDB支持事务,且MySQL默认的就是innodb引擎,只要将引擎配置成innodb即可。至于如何防止数据库的脏度这个问题,我们是需要了解数据库事务的隔离级别:
大致有4中
(1)read uncommitted :读取了未提交的数据,就是脏读
(2)read committed:读取已提交的数据,可以解决脏读的问题
(3)repeatable read:可重复读,可以解决脏读 和 不可重复读 ,这是MySQL默认的隔离级别
(4)serializable:串行化,可以解决 脏读 不可重复读 和 虚读
由数据库的隔离级别我们可以发现,只要将数据库的隔离级别不设置成read uncommitted 就可以解决数据库的脏读问题
总结:数据库的事务和隔离级别这一块还是很重要的,至于什么是事务(ACID)自己可以去看看。
(注*)这里拓展一个知识点关于MySQL的事务处理过程
(1)在说MySQL的事务处理过程之前我们先来了解下innodbBuffer(数据缓冲) innodb_buffer_pool_size:是innodb的缓存,可以缓存索引和一些实际的数据。
(2)innodb_buffer_pool_size参数主要是用来设置innodb的Buffer的大小,可以通过设置来提高我们innodb引擎的性能,其默认值为128M
(3).事务处理过程
1.首先事务在buffer中对数据进行修改
2.事务的变化记录在事务日志中
3.在合适的时机同步事务日志中的数据到数据库中
何时同步事务,通过设置innodb_flush_log_at_trx_commit来修改事务日志同步时机:
innodb_flush_log_at_trx_commit = 0;表示每隔一秒同步一次
innodb_flush_log_at_trx_commit = 1;默认设置,表示每一次事务完成之后同步一次
innodb_flush_log_at_trx_commit = 2;事务完成之后,先写到事务日志文件中,覆盖之前数据即可。
但是各自参数都有自己的缺点:参数设置为0性能最差,2不能完全保证数据是写到数据文件中,如果宕机,可能会有数据丢失现象,但性能最高;1的性能和安全性居中;
4.如何可以让一个索引失效?
这个问题很好答的,常见的让索引失效的有:
(1)条件中有or
(2)查询模糊匹配时在开头使用%
(3)MySQL使用全表扫描时,不会使用索引
(4)如果MySQL的索引的列是字符串类型,一定要用引号引用起来
(5)使用不等于(!= 或者<>)的时候MySQL 无法使用索引
(6)过滤字段使用了函数运算后(如abs(column)),MySQL 无法使用索引
(7)Join 语句中Join 条件字段类型不一致的时候MySQL 无法使用索引
5.MySQL的执行流程有了解吗?
先上图:
image.png
简单的说一下我自己的理解:
(1).客户端发送一条查询的sql语句到服务器。
(2).服务器先是一些权限的检查,然后去缓存中去查看,如果命中了缓存,直接将结果返回。
(3).如果缓存中没有,然后解析器进行sql的解析、预处理,然后通过查询优化器根据我们优化后的sql进行相关表的数据统计、计算等操作,并生成一份执行计划。
(4).服务器根据优化器生成的执行计划去调用对应的引擎API来执行sql
(5).将结果返回给客户端
6.左连接(left join)’inner、右连接、exists的区别?
1.左连接在查询的过程中是以左边表为主,即左边表全查,右边表只查自己需要的数据。
2.inner实质为等值查询,只查两张表中共有的数据
3.右连接:跟左连接一样。
4.exists:返回结果是bool型,exists的效率比in查询要高(很少用,自己可以去试试,这是面试官问我的),顺便看看联合查询等。
7.常见的索引和优缺点?
索引就是将无序的数据变成有序的查询, 索引是一个文件,所以不是索引越多越好,这样会导致维护的成本变大。
常见的索引有:
(1).Normal普通索引,即一个索引值后面可以关联多个值
(2).Unique唯一索引:一个索引值后面只允许有一个值。
(3).FullText全文检索:innodb不支持,只有myisam支持
8.B-Tree和hash的区别?
1 .B-Tree:是使用平衡树来实现的,也是MySQL中使用最多的索引类型,如主键,其中b-Tree中保存的数据是按照一定的顺序来保存的,支持范围查询
2.hash:以索引作为hash运算,将结果保存到hash表中,一般使用较少。
缺点:
(1).hash只适合精确查找,不适合范围查找
(2).大量的使用hash索引,会导致性能降低
9.MySQL的复合索引了解吗?
(1).复合索引:是由多列值组成的索引,且之间是有顺序的。
(2).复合索引的原理:就是类似orderby(orderby后面可以跟多个排序条件1,条件2...);就是在排序和分组(创建倒排表的时候),按照多个列进行排序和合并。
如:
......
SELECT * FROM user WHERE actionTime < 'xxxxx' AND account_id = 5 可以使用actionTime+account_id的复合索引;
SELECT * FROM userWHERE actionTime < 'xxxxx' 可以使用actionTime+account_id的复合索引;
SELECT * FROM user WHERE account_id = 5 不可以使用actionTime+account_id的复合索引;
SELECT * FROM user WHERE account_id = 5 AND actionTime < 'xxxxx' 不可以使用actionTime+account_id的复合索引;
(3).复合索引在查询的时候,遵守向左原则
(4).在实际的开发中,复合索引是我们经常使用的。
10.MySQL的主从是如何配置的,以及原理和为什么要用主从?
1.先来看看MySQL主从简单的草图来看看(勿怪)
主从.png
1.简单的来说一下为啥需要主从,图中画了我们的应用进行了集群, 前端(uiweb)和后端(mgrtool)。
当我们的服务请求过多时,可以断定是服务器的压力过大,需要进行服务的负载均衡,尤其是前端的。
2.如果请求过多,静态的页面还好,但是动态数据却很卡,说明MySQL服务器要处理的请求太多,我们需要处理MySQL服务器的压力,可以配置缓存机制,这里是配置了MySQL的主从。
3.配置主从却不是难点,将我们的MySQL进行拆分,主用来写操作,从用来读操作,问题是如何将主从的数据进行同步,这是关键。(感兴趣的可以去看看)
4.主从同步,我简单的说一下自己的看法,既然涉及到了数据的同步,会涉及到延迟操作,也就是你完全有可能会读到脏数据(脏读),所以在实际的业务中,需要在从MySQL上进行读操作时,一定对实时性和脏数据有一定容忍度的数据,比如:登录日志、一些相关的报表等。
5.主从的原理
先上图:
原理.png
1.主从同步,必须是所有的Master上的DML和DDL语句在从Salve上正确的执行一次,且结果一样。
2.其次是打开主服务器上的bin-log文件(二进制文件),bin-log可以记录所有的在MySQL上执行的DML+DDL+TCL操作。
3.MySQL是使用被动注册的方式来让从MySQL请求同步主MySQL的bin-log文件。
4.从MYSQL后台一个线程发送一个请求,到主服务器请求更新数据。
5.主MYSQL后台一个线程接收到从MYSQL发送的请求,然后读取bin-log文件中指定的内容,并放在从MYSQL的请求响应中。
6.从MYSQL的请求带回同步的数据,然后写在从MYSQL中的relay-log(重做日志)中;relay-log中记录的就是从主MYSQL中请求回来的哪些SQL数据;
7.从MYSQL后台一个线程专门用于从relay-log中读取同步回来的SQL,并写入到从MYSQL中,完成同步;
这就是主从同步的大致原理
11.MySQL的读写分离
简单的说是配置路由,在你具体的业务中的某一个方法只能有且定位到唯一的一个数据库中。(具体的过程自己去百度看看)
四、常用框架的面试题
面试框架是必问的东西,如mybatis、spring、springMVC、springboot等,每个面试官的问法不一样,但基本的回答核心都是差不多的,最烦的是问你读过spring的源码?说实话,没读多,我也发现了,要想去正真的大型互联网去,框架源码你是必须要知道的东西,我也真准备去看看,感觉有点难,读源码不是让我们去抄袭怎么写,我认为最主要的是要了解框架的底层的设计思想,如反射、和设计模式是框架的核心,与其说是Java的天下,还不说是spring的天下,建议老铁们去看看源码,反正也看不懂....,别问,难受,先来说spring的。
image.png1.不管你是几年springmvc的执行流程是必问的东西,这也没啥好说的,没有固定的答案只能说上几个关键字如前端控制器做了什么事,handlerMapping (处理器映射器)、适配器等,简单的说说就可以了。可能在handlerMapping 这里的返回一串执行链进行接着问,想了解的自己去看看。
2.Spring中service是单例吗?
答:我们知道spring容器帮我们创建bean和管理bean的生命周期,所以在spring的容器中所有的一切都是bean,既然是bean默认是单例的,可以通过作用于scope来配置成多例的。
3.spring中书写的Controller是安全的吗?
答:这个问题也很好回答,可能首次问到会懵逼,Controller也是spring容器中的bean,单例的,存在线程不安全,固然是不安全的,举个简单的例子,这就涉及到多个线程竞争一个资源的问题,我们的controller是那个资源,多个用户是线程。如何解决这个问题,很简单,我们可以将controller配置成多例的,每一次访问都会创建一个新的controller,这样就不会是多个线程访问时造成线程不安全问题,这只能解决一小部分问题,实际业务中肯定不会是这样的。
如:我现在有一个商城的限时秒杀活动,同样是访问到我们这个controller,这样大的并发量是无法承载的,假如时间一到我有100万用户来请求我们的controller,简单的做法是我可以接口之前进行MQ(消息队列)处理,大不了mq集群,这样可以来缓解controller压力,然后挨个挨个去处理即可。
4.spring 的常见的设计模式有哪些?
这是一个面试官问我的,玛德变向的问我读没读过源码没,我就说了4中,后来百度看了一些,大概有spring中用到了9中,这里简单的说一下
1.工厂模式:用来创建bean
2.工厂方法:FactoryBean接口
实现原理:实现了FactoryBean接口bean是叫做factory的bean,调用的是bean的getObject方法
典型的是spring和mybatis的结合
3.单例模式
Spring的依赖注入bean是默认是单例的
4.适配器模式
实现的方式:SpringMVC的适配器的HandlerAdapter
实现的原理:HandlerAdapter根据Handler的规则去执行不同的Handler。
5.代理模式
实现方式是Spring的方式是Aop
6.观察者模式
使用场景:listener的实现
具体的实现:
(1).ApplicationEvent(事件)
(2)该事件继承jdk的EventObject,所有的 事件都需要继承.ApplicationEvent(事件)
且通过构造器参数来得到事件源
该类的实现类是ApplicationContextEvent(容器事件)
image.png
image.png
(3).ApplicationListener(事件监听器)
该类继承jdk的EventListener,所有的监听器都要实现这个接口
该接口中只有一个方法onApplicationEvent()方法,用来接受.ApplicationListener的子类或者对象作为参数,在方法中通过不同的事件进行相应的处理
当事件触发所有的监听器时,都会接受到消息
image.png
ApplicationContext(事件源)
实现了ApplicationEventPublisher接口
主要是负责读取bean的配置文件,管理bean的生命周期,(ioc容器)
image.png
8.策略模式
实现方式:Spring框架的资源访问Resource接口
本来要截下源码的,没导包,所以简单的说一下。
9.模板方法模式
Spring的jdbc的模板
spring中有一套也是实现了jdbc的模板,如图:
模板.png
这是spring中常见的常见的设计模式
5.说说spring?
答:这个问题实质是想问一下spring中的两大核心模块,分别是IOC和AOP,各自的特点和使用的场景等
6.spring中的BeanFactory和FactoryBean的区别
答:1.BeanFactory主要是侧重于Factory,是工厂,是IOC容器最基本的最基本的接口,而FactoryBean是侧重于Bean,也就是具体的来创建和管理bean的工厂。
ww.png
TIM截图20181128203340.png
TIM截图20181128203418.png
上面是BeanFactory的接口,只提供了一个接口供子类去实现,再来看FactoryBean的
bean1.png
bean2.png从代码中可以看出,FactoryBean也是一个接口,可以在注释中大概的看出,实现改接口的类返回的实例是由它来管理的。
bean3.png这是该接口中获取实例的一个方法。
bean4.png
由上面的两个源码知道,由FactoryBean创建的Bean在ioc容器中默认是单例的。
7.简单的阐述下spring和springboot的优缺点
(1).spring主要的缺点是需要配置很多xml,需要依靠外界的容器(tomcat)环境才能测试启动。
(2).springboot的优点:
1.简化了繁琐的xml配置,内置了tomcat容器
2.可以独立运行spring的项目
3.简化了pom依赖
4.进行相关配置的自动装配等。
8.springboot的常见的注解和各自的作用
1.SpringbootConfiguration (配置标签)
是由EnableAutoConfiguration(自动配置)组成,其中 SpringbootConfiguration 标签本质是一个@Configuration,代表spring的主配置类
2.EnableAutoConfiguration(自动配置)可通过spring-boot-autoCoonfiguration包中的META-INF/spring.factories文件中的配置项中,其底层是由@EnableAutoConfiguration标签引入AutoConfigurationImportSelector类中,和使用spring的SpringFactoryLoader类实现加载
3.@PropertySource的作用是引入其他的配置文件
MyBatis核心对象及操作流程.png9.MyBatis的执行流程
一张图可以说明一切,如图:
MyBatis的底层实质还是JDBC的执行流程,多了一层封装的过程,这也是问的最扯淡的问题。
- 井号# 和$的区别
(1).两者都可以获取对象中的属性
(2). 使用#传递的参数会先转换为,无论传递是什么类型数据都会带一个单引号。
(3).使用美元符号(不要问我为哈这样写,这里语法解析错误)传递的参数,直接把值作为SQL语句的一部分。
11.mybatis的延迟加载如何配置?
如图:
peizhi.png
12.常用的动态sql(这个自己去看看),还有就是项目中分页是如何使用的,这样答就可以了用的MySQL的limit即可。
13.有个阿里的外包技术总监问我这样一个问题,大概是这样的,我们是如何去执行具体的sql语句的,这样答:通过namespace+id可以。
14.mapper接口中,@param注解的底层是如何实现的
答:在mapper接口中,我们往往需要借助于注解param来进行多个参数的封装,其实质底层是一个map组成
如图:
wqwqwqw.png
至于该注解是底层如何实现的,感兴趣的自己去看看
15.spring的两种事务处理机制
(1).spring的编程式事务
使用transactionTemplate 或者底层的Api的PlatformTransactionManager来进行书写代码的方式处理事务,比声明式更细粒度,spring推荐使用 transactionTemplate;
且事务和业务逻辑的耦合很高.
(2).声明式事务
声明式事务是基于AOP之上的,其本质是在业务方法执行前或者后进行事务操作,然后根据执行的结果来判断是提交事务还是回滚事务.
优点:将业务逻辑和事务分离开来,利于维护
缺点:声明式事务只能作用到方法级别
常见的两种方式是通过配置xml和注解的方式来实现
2.事务的传播规则
image.png
五、分布式面试问题
在如今的开发趋势中,分布式和微服务是我们必备的技能,也是面试官喜欢问的问题,在实际的开发中本人使用的是dubbo+zookeeper分布式架构,具体的来看面试官是如何提问的,主要是结合结合自己的项目来说。
1.简单的阐述下分布式的好处,结合自己的项目
2.Dubbo了解吗?dubbo的底层协议是?
1.我们先来说一下Dubbo:
我是这样解答的,dubbo是一个阿里巴巴开发的开源分布式服务框架
(2).致力于提供高性能和透明化的RPC远程服务调用
(3).每天为2,000+个服务提供3,000,000,000+次访问量支持。
这是dubbo的优点,接下来说了Dubbo架构原理:
image.png
这是dubbo官网提供的Dubbo架构图,上图也说明了dubbo的执行流程
(1).服务容器负责启动,加载,运行服务提供者。
(2).服务提供者在启动时,向注册中心注册自己提供的服务
(3).服务消费者在启动时,向注册中心订阅自己所需的服务
(4).注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者。
(5).服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心。
上面的这5步是对该架构图的文字阐述,至于dubbo的底层协议是tcp协议,官方推荐我们使用dubbo协议,因此我在项目中是使用dubbo协议的。
3.dubbo的序列化方式
答:dubbo默认的序列化方式是Hessian序列化
4.有个面试官问我读过dubbo源码吗?
没读过,dubbo是一个rpc框架,rpc的原理和序列化和反序列化的过程都得清楚。
5.在你们的项目中是如何配置dubbo超时的
一张图告诉你:
chashi.png
服务端和消费端都配置了超时时间
6.你们的项目中zookeeper主要是用来干嘛的?
答:zookeeper是dubbo的服务注册中心,其 主要的作用是为了解决为消费者服务地址发现的问题,因为在集群的环境下,传统的服务消费者直接记录服务提供者信息的服务地址很难管理,只要提供者地址信息发生变化消费者也必须进行相应变更,并且这种方式没办法做服务的负载均衡,引入注册中心后,同时也引入了服务注册的概念,服务提供者只需要将自己信息与所提供的服务地址注册到注册中心即可,而消费者则只需要关注自己需要调用某个服务,然后直接从注册中心获取相关提供者的信息即可,注册中心还会与提供者保持着心跳,一旦提供者发生变动,通过订阅的形式注册中心会将相关的变动通知到消费者,此时消费者便可以做到自动调整可调用的提供者信息。
7.你们的服务在运行中,如果我的注册中心挂掉了还能正常的去调用服务吗?
答:是可以的,因为dubbo在获取注册中心地址时会将返回的提供者地址缓存在本地,在提供者地址未改变的情况下是根据缓存数据调用服务的而非每次都向注册中心获取
8.RPC了解吗?
答:RPC就是远程过程调用协议,他是一种协议或者说是一种技术的标准,它的原理其实就是对象的序列化和反序列化。这里有一篇博客https://www.cnblogs.com/swordfall/p/8683905.html大家可以看看,底层的rpc原理还是利用反射创建的代理对象去请求,在经过网络传输时先是序列化--------->到服务器时,进行反序列化---------->服务器将所需的方法或者参数等进行序列化---------------->到客户端时反序列化的过程,是通过BIO来完成,采用了jdk自带的ObjectInputStream和ObjectOutputStream来实现,这是原生的。
9.zookeeper的结构了解吗?
答:一张图让你明白:
image.png
其中(/)表示节点路径,zookeeper是一种树形结构,下面的是节点,节点大致分为持久性、临时节点、有序节点,其实这里的节点跟我们的集合map类似,是一种key-value的结构特点,这里在提一点学习zookeeper不难,有两个知识点弄明白就可以了,一是节点的特点和创建,还有就是节点的观察者(watcher),这要的作用是监听节点的创建、删除、更新等。
10.zookeeper的集群
答:zookeeper集群的过程是投票选择leader的过程,投票选举遵守半数机制,即集群中半数以上机器存活,集群可用;
如图:
image.png
大致的流程是这样,假设有三个集群:
1.当sid:1启动时,先去查看集群的数量是否大于半数,如果大于开始投票
2.默认会给自己投票如:1投票:(sid:1.zxid:5) 1,其中sid为投票的id zxid为投票的事务,假设编号为5
3.此时有三个集群,当sid:2启动时,开始投票,也投自己如:2投票:(sid:2.zxid:6) 2
4.(4)sid:1 和sid:2同时将自己的投票广播,两者彼此收到了各自的投票,然后对比sid大的优先称为leader,sid:1发现自己的id小于2的,重新投票,此时2为2票,成为了leader,sid:1为folower(随从),如果两个id相等,可通过zxid来投,大的优先
5.启动sid:3,不需要在投票,直接成为了folower
11 为什么使用redis?
答:(1).性能极高 – Redis 能支持超过 10W 次每秒的读写频率
(2).丰富的数据类型
(3).所有的操作时原子性的,也就是支持事务
12.Redis是单例吗?
答:redis是单例的
13.Redis有一个慢查询,会印象别的操作吗?(如支付接口)
答:会影响别的操作的,先来看看redis的慢查询操作过程:
发送命令 --------- 排队--------执行命令----------返回结果;这主要是因为redis是单例的:
image.png
有图我们可以看到慢查询的过程中是需要等待的,假如此时有网络延迟,可能会导致阻塞现象。
一般的解决办法是:
1.设置慢查询的队列长度:slowlog-max-len = 128(默认值)
2.设置满查询的记录阀值:slowlog - slower-than =10000 该表示超过10毫秒就会记录到满查询对列中
13.你们的项目中哪些地方用到了redis,是如何做的?
答:这里我简单说一下自己的,还是结合自己的项目来说的,redis在项目中主要用于缓存,主要存放用户的信息(token)、帖子点赞、点赞数等。
14.Redis中有哪些数据结构?
答:传统意义上讲,redis一共为我们提供了五种数据结构,分别为:String、List、Set、Sorted Set、Hash,但在Redis 3.2 之后提供了一个新的功能 GEO,你也可以把它理解为一个新的数据结构,他提供了对地理位置相关的功能,你可以存储经纬度来进行相关的操作,类似实现微信摇一摇、附近的人等等与地理位置相关的功能
15.如果Redis挂了怎么办?数据会不会丢失?
答:项目中redis是集群的操作,有1个Master和1个Salve,另外还用了Redis Sentinel(哨兵)监控来提高Redis的可用性,当 主Redis 挂了之后哨兵会将从Redis提升为主Redis。
数据丢失的话,只有当redis都挂掉了,我们配置了rdb和aof两种策略来对redis中的数据进行持久化,aof配置的每秒同步一次,aof和rdb是redis的两种数据持久化的方式,rdb是快照的方式。两者区别可以自己去看看。
16.项目中的接口如何处理重复的请求?
答:用redis来缓存
重复的请求是在很短的时间内请求的,我们可以用一个计数器来解决这个问题,在接口的开始之前,定义一个计时器,同一个请求过来计时器+1,当计时器>1不处理请求。
17.RESTful是什么?有什么特点?为什么要用它?
答:RESTful是一种架构理论或者说一种软件设计风格,它的特点是使用RESTful作为指导原则设计出来的资源路径只能体现资源本身,不能体现资源的表现形式和资源的状态转移,资源的表现形式和状态转移应该有统一接口来表现.使用了RESTful后我们的资源路径更直观的体现出资源,并且针对同一资源的操作对外提供的资源路径会大大减少,这有利于我们管理资源路径,还有就是大家都按RESTful的原则来设计,这样我们的项目更规范
这个本来就没啥好说的。
18.项目中Nginx主要是用来干嘛的?
答:Nginx是http服务器,进行前后端的分离,同时也是我们应用的第一道屏障,当请求过来时,通过负载均衡和反向代理我们进行请求的轮询,缓解了服务器(tomcat)的压力,我们tomcat的压测大概是500-700之间,同时Nginx是静态服务器,我们可以将一些比较大的资源存在Nginx上,如:图片。
注意:学习Nginx可以从它 的配置文件Nginx.conf入手。大家可以去看看.....
19..Nginx怎么分配请求?如果有2台主机,nginx是怎么分配到不同tomcat的?
答:Nginx分配请求的方式有5中,分别是:
(1).轮询(默认):每个请求按时间顺序逐一分配到不同的后端服务器,如果后端服务器down掉,能自动剔除。
(2).weight(指定轮询比率):weight和访问比率成正比,用于后端服务器性能不均的情况。
(3).ip_hash:每个请求按访问ip的hash结果分配,这样每个访客固定访问一个后端服务器,可以解决session的问题。
(4).fair:按后端服务器的响应时间来分配请求,响应时间短的优先分配
(5).url_hash:按访问url的hash结果来分配请求,使每个url定向到同一个后端服务器,后端服务器为缓存时比较有效。
image.png这里多说一点,就是Nginx的反向代理的实现过程,我是在linux上玩的如图:
image.png简单的说下步骤,在Linux下的usr目录下:
(1).在/usr/local/tomcat目录下,启动Tomcat
(2).进入Nginx目录下的nginx.conf
(3).使用命令vi nginx.conf 进行编辑
(4).保存退出
注意:我这里将tomcat和nginx放在了Linux下的在/usr目录下
我们还可以通过ngnix来获取真实的ip,配置如下:
(1).进入 nginx.conf
(2).在server 下的匹配路径下(location)加上如下的命令
(3).保存退出
Nginx的负载均衡配置如下:
image.png
负载均衡,这里我们需要开启两个服务器.具体的过程如:
(1).拷贝cp -r /usr/local/tomcat /usr/local/tomcat2
(2).cd 到/usr/local/tomcat2/conf/server.xml中修改端口等
(3).启动Tomcat2进行测试可通过查看进程的操作如:netstat -ntlp即可
(4).cd 到 /usr/local/ngnix/conf/nginx.conf
(5).在http下加入 upstream myapp {
server localhost:8080 weight=1 max_fails=2 fail_timeout=30s;
server localhost:8081 weight=1 max_fails=2 fail_timeout=30s;
} 如图:
(6).修改配置的反向代理中的地址
image.png
已上就是简单nginx的玩法
image.png20.Mq消息重发会对业务有影响吗?如何处理?
答:会影响,我们可以将mq内部做成幂等性的
具体的做法:对于每条消息的发送,mq内部生成唯一的全局唯一的与业务无关的id,当mq -server接收到消息时,通过id判断消息是否发送重复,在决定将消息是否落地到db中
1、发送端MQ-client(消息生产者:Producer)将消息发送给MQ-server;
2、MQ-server将消息落地;
3、MQ-server回ACK给MQ-client(Producer);
4、MQ-server将消息发送给消息接受端MQ-client(消息消费者:Customer);
5、MQ-client(Customer)消费接受到消息后发送ACK给MQ-server;
6、MQ-server将落地消息删除
举例:
为了保证消息必达,MQ使用了消息超时、重传、确认机制。使得消息可能被重复发送,如上图中,由于网络不可达原因:3和5中断,可能导致消息重发。消息生产者a收不到MQ-server的ACK,重复向MQ-server发送消息。MQ-server收不到消息消费者b的ACK,重复向消息消费者b发消息。
21.项目中为什么要用ActiveMQ?
ActiveMq的应用场景有:1,存在并发访问的业务 2,耗时比较久的业务 3,需要解耦出来的业务,我们项目中出现了ActiveMQ可以解决的场景,所以我们用了ActiveMQ.
22.MQ有哪几种消息签收方式?
ActiveMQ的消息签收方式总的来说4中,如果使用的是session是有事务的,那么消息的签收是提交事务就签收的,如果是不带事务的session,那么消息的签收方式有3种,分别是,自动签收,手动签收,不必须签收.
23.MQ的消息传送模式有哪些?
消息的传送模式有:持久化消息和非持久化消息,持久化消息是会把消息持久化到磁盘的,如果消息没有被消费,服务器就挂掉了,消息也不会丢失,服务器重启后还是会把消息从磁盘读取到内存中,并且在消息没有签收之前是不会被删除的.非持久化消息就只存在内存中,这样服务器如果挂掉了数据会丢失.
24.MQ的Topic和Queue有什么区别
1.queue和topic都是消息的目的地.JMS规范中定义了两种消息传递域,分别是点对点和发布/订阅消息传递域,使用点对点消息传递域发送的消息的目的地称为queue,使用发布/订阅消息传递域发送的消息的目的地称为topic
2.Queue的特点是每个消息只能有一个消费者
3.Topic的特点是每个消息可以有多个消费者,并且生产者和消费者之间有时间上的相关性,订阅一个主题的消费者只能消费自它订阅之后发布的消息。
25.了解 Docker 吗?
答:Docker 可以简单理解为一个轻量级的虚拟机,是技术容器化,可以使我们的应用运行环境独立起来,不受宿主机软件的影响,方便部署与持续集成,并且对于运维来说 Docker 提供了一种比虚拟机性能更优操作更简单的虚拟化解决方案。
- Docker 容器共享数据有几种方式?分别如何实现?
(1).一个是数据卷(volume)
(2).数据卷容器
其两者的作用都是为了实现容器内的数据与容器外的数据共享
实现方式总共有三种:
(1).使用 Dockerfile 构建容器时,使用 VOLUME 指令指定数据卷映射的目录
(2).是在创建容器时使用 –v 参数实现容器内目录与宿主机目录的映射
(3).数据卷容器就是先创建一个已经分配好数据卷的容器,然后不管该容器是否有启动,都可以在启动别的容器时使用 --volume-from 指定容器名便可以在新的容器中使用原有容器已经配置好的数据卷了
27.进入 Docker 容器的几种方式
答:共有三种方式,Docker 为我们提供了两种方式 attach 和 exec 子命令。可以使用nsenter 工具进入容器中.
28.docker-compose 和 Dockerfile 的区别是什么?
docker-compose 实际是 docker 为了方便我们管理容器,创建容器提供的一个工具,它规范了一套 yaml 语法的配置文件,我们可以将原本需要写一长串的容器启动命令配置到该配置文件中,然后直接使用 docker-compose up 则可以将我们配置的好的所有容器启动起来,并可以快速实现对容器的启动、停止、重启、删除等操作。而 Dockerfile 则是 Docker 规范的一套自动构建镜像的指令集,你也可以把他看做一个配置文件,Docker 规范了 Dockerfile 编写的一套指令,我们通过在 Dockerfile 中配置完构建一个镜像的所有指令后,只需要通过 docker build 命令来构建我们的镜像即可,所以 docker-compose 是用来创建/管理容器的,而 Dockerfile 则是用来构建镜像的
六、工具常见的面试题
1.Git的commit之后如何回滚?
用命令git reset
常见的git的操作:
创建本地分支:git -branch
合并自己的分支:git checkout
提交到分支:git add
查看是否提交成功;:git status
提交代码:git commit
如果忘记建分支了,已经修改了代码在主分支
使用git stash 保存到暂存区
不管你前面的东西大的怎么样,git是你必须掌握的东西
2.Linux都用过哪些命令
这个自己去练练
有一个面试官这样问我,如果我远程复制文件用那个命令,是scp
3.Maven的生命周期和作用
(1).clean生命周期:清理项目,包括了三个解析(phase)阶段
1.pre-clean:执行清理前需要完成的工作
2.Clean:清理上一次的构建项目的文件
3.Post-clean:执行清理后需要完成的工作
(2).default生命周期:构建项目需要的phase
1.validate:验证工程是否正确,所有需要的资源是否可用
2.Compile:编译项目的源代码
3.Package:将已编译的代码进行打包处理,如:jar
4.Install:将大成的包安装到本地仓库中,这样可以被其他工程来依赖
(3).site生命周期:建立和发布项目的站点
1.pre-site:生成项目站点需要的完成的工作
2.Site:生成项目站点文档
3.post-site:生成项目站点之后需要的完成的工作
4.site-deploy:将项目站点发布到服务器上
4.IDEA和eclipse的区别
在面试的过程中我觉得这个问题是最傻逼,我没说出来,我记得我就说了IDEA好用,这里忽略,我们来看最大的区别:
(1).idea中的project相当于eclipse的workspace
(2)Idea中的module相当于eclipse中的project
(3)Idea中的project可以包含多个module
5.Git解决代码冲突问题?
(1).pull代码
(2).同步,查看冲突代码
(3).双击红色方块(冲突的文件)保存到本地的是最新的
(4).提交修该
(5).在进行commit
(6).在pull一下代码即可
6.Maven中项目的继承依赖包可以怎么管理
1 所有子项目都需要使用的依赖我们是配置到<dependencys>中
2 对于有个别项目需要需要使用到的依赖,我们会配置到parent<dependency-management>中,用于版本的统一控制,其他需要使用到该依赖的项目只需要直接引入就好,不需要再加入版本号
七、并发编程问题
1.线程池的设计模式常用有几种
(1).代理模式
(2).Thread-Per-Message-Pattern:该线程是对于每一个命令或者请求都会分配一个线程,由这个线程执行工作,它将委托消息的一端和执行消息的一端,用两个不同的线程实现。
该线程包括:
Request(委托人):消息发送端或者命令请求端
Host(参与者):接受消息的请求,负责为每一个消息分配一个工作线程
Worker参与者:具体的执行Request的任务线程,并且由Host参与者来启动
因为 Thread-Per-Message-Pattern:每一次请求都会生成一个新的线程,这样是很耗时间的,所以用WOrker Thread来重复利用启动的线程
2.concurrentHashMap 原理 (自己可以去看看)
image.png3.线程的状态有哪些?
(1).新建状态(new) :使用new创建一个线程对象,仅仅在堆中分配内存空间,在调用start()方法前;
(2).可运行状态(runnable):分成两种状态,ready和running。分别表示就绪状态和运行状态.
就绪状态:线程对象调用start方法之后,等待JVM的调度(此时该线程并没有运行);
运行状态:线程对象获得JVM调度,如果存在多个CPU,那么允许多个线程并行运行;
(3). 阻塞状态(blocked):正在运行的线程因为某些原因放弃CPU,暂时停止运行,就会进入阻塞状态
此时JVM不会给线程分配CPU,直到线程重新进入就绪状态,才有机会转到运行状态.
阻塞状态只能先进入就绪状态,不能直接进入运行状态.
(4).等待状态(waiting)(等待状态只能被其他线程唤醒):此时使用的无参数的wait方法,
(5).计时等待状态(timed waiting)(使用了带参数的wait方法或者sleep方法)
1):当线程处于运行过程时,调用了wait(long time)方法,此时JVM把当前线程存在对象等待池中.
2):当前线程执行了sleep(long time)方法.
注:线程对象的状态存放在Thread类的内部类(State)中:Thread.State类其实是一个枚举类
如图:
建议大家可以试着将这张图画下来,因为我是在面试时当场画的。
4.双重锁的单例,其中锁的作用分别是?
先是手写饿汉式单例,是线程安全的,接着问锁的作用,大概是这样的一把琐是用来锁方法,一把是锁返回值的
- 创建线程的两种方式,还有各自的好处
答:一是继承Thread类,一种是实现runnable的接口,不多说,当然是依赖倒转这种方式更好一点(面向接口编程)。
6.start、和run的区别
答:start是开启一个线程、而run是一个普通方法
thread1.png7.ThreadLocal使用过吗?以及在什么地方使用的
答:这个类是重点,建议大家好好看看,我这里简单的说一下:
(1).首先是本地线程
(2).线程(Thread)内部都有一个Map(ThreadLocalMap)
(3).map中以当前线程为key,以线程中的变量为value
(4).也是我们springmvc获取对象的基本操作
使用的场景:
最常见的是用来解决数据库连接、Session管理等
简单的看一下它的源码:
如图:
thread2.png首先ThreadLocal不是Java.util.concurent包下的,而是Java.lang包下的,这是它接口的声明,我们再来看常见的方法
thread3.png初始化值的,默认返回的是null
thread4.png thread5.png这是它的get方法,用来获取当前线程上绑定的变量,我们再来看:
thread6.png这是set方法,给当前线程来绑定变量
thread7.png这是它内部维护的一个map
thread8.png我们看到默认的容量初始值跟map集合的一样,同样内部维护着一个entry数组,再来看:
这是它内部维护的entry数组,以上就是简单的对ThreadLocal的了解,感兴趣的可以去看看
8.什么是线程池?
答:这个问题可以去跟连接池对比的看一下,都是为了资源的可利用才设计出来的。
lock1.png9.synchronizad和lock的区别?
答:lock是对象,提供了很多丰富的方法,而synchronizad只是一个Java中的关键字而已,这里简单说一下,自己去看看。
我们来看看lock的源码:
lock2.png
lock3.png
lock4.png这个方法很重要,之后的分布式锁是通过它来实现的。
lock5.png
relock1.png再来看它的实现类重入锁
至于后面的方法自己去看,反正我看不懂...
10.i++线程安全的问题?
答:实际上i++会造成线程不安全的问题,详情自己去看,可以用synchronizad来解决安全问题,但会影响性能。
更多关于多线程的常见面试题,给大家推荐一篇博客。博主总结的很详细https://mp.weixin.qq.com/s?__biz=MzAwOTE3NDY5OA==&mid=2647907287&idx=1&sn=f3b3c5f9120c437ec9487c6a8e65778e&chksm=8344d012b4335904ffdc709db9bf51684001df1145683136700c42031eca6152af3f656d0b31&mpshare=1&scene=1&srcid=1201a6of6GPqvA7PkxYLxCIN#rd
八、其他常见的面试题
1.网络通信TCP和UDP的区别
答:(1)Tcp是面向连接的协议,在发送数据前需要建立三次握手。
(2).UDP不需要连接
(3)TCP可以保证数据的正确性,而UDP可能丢包。
(4)TCP保证数据的传输顺序,UDP不保证。
2.HTTPS原理
https的作用是为了客户端与服务器之间通讯的安全性,实际上https是工作在SSL上的http协议。
1.在执行传输之前,需要客户端(浏览器)和服务端(tomcat)进行一次握手协议,通过握手协议确定服务器端的合法性和确定双方在传输过程中使用的密码信息;
2.通信过程使用密码信息完成数据的加密传输和完整性校验;
3.在开发中有没有遇到印象深刻的问题?
4.session和cookice的区别
5.类的加载顺序
1.父类静态代码块;
2.子类静态代码块;
3.父类非静态代码块;
4.父类构造函数;
5.子类非静态代码块;
6.子类构造函数;
这个问题我就补充到这,一般面试可能不会问道,但笔试题中很常见
6.单点登录如何实现?
答: SSO的定义是在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统。
1.client1验证是否登陆:
判断client1的session中是否存在isLogin为true即表示已登陆
2.server验证是否登陆使用:
判断server的session中是否存在isLogin为true即表示已登陆
3.登陆页面统一使用认证系统的登陆页面
但是必须带上原来用户访问client1地址
4.登陆后创建全局会话
server的session存储token及isLogin两个参数
并且存储到map中,该map<token,session>主要存储已登录的所有信息
5.重新跳转到client1时需要带上令牌参数
6.client1的拦截器获取到令牌参数需要进行校验
使用webservice发送请求到server进行验证
判断map中是否存在该token,如果是则代表已登陆
7.令牌验证成功,则创建局部会话
client1的session存储token及isLogin两个参数
8.访问client2时肯定没有局部会话,此时跳转到server
来进行验证是否已经登陆,
如果是则重定向到client2的页面中
并进行令牌验证
验证有效则创建局部会话
client2的session存储token及isLogin两个参数
7.常见runtimeexception有哪些?
8.常见的设计模式有哪些?
9.Tomcat的优化
10JVM参数的调优
(1).增加JVM的堆内存
代码:
修该参数: Java_OPTS=’-XMs256m -Xmx 526m’
表示初始值为253MB ,最大内存为526MB
(2).调整Tomcat的线程参数
在server.xml中<Connector>配置
主要配置最大线程数(maxThreads)和接受的线程总数acceptAcount
image.png11.gc的过程和策略
先来看看Java中的堆栈图
有图可以看出:Heap(堆内存)=eden+2survivor(年轻代)+ParOldGen(老生代)+Perm(jdk8以前)。
Gc的执行过程:
(1).首次创建一个对象时,首先是在新生代进行内存空间的分配,当到了100%,再也无法分配内存。
(2)触发gc算法进行一部分不在使用的对象进行回收,与此同时将剩余的对象存放到survivor(永生代),这个时候有一个计数器来为每个对象的age+1,一直重复该动作
(3)当age到达一个数字时,触发老年代的gc算法进行回收,将对象保存到老年代区(old)
(4)因为不断的有对象进入老年代区,当老年代的内存+新生代到达内存的最大的临界值时,触发full gc全部回收。
Gc的策略:
1.引用计数:
原理:为每个对象的引用加1,删除一个引用即引用计数减1,当触发gc算法时,回收引用计数为即可。缺点:加入有两个循环引用时,该算法无法处理。
2.标记-清除
原理:该算法分为两部分,首先标记那些有引用的对象,第二部分时遍历整个堆内存,将未标记的对象清除。
缺点:需要停止真个应用,会产生内存碎片
3.复制
原理:将内存空间划分成两个相等的区域,但是只需要使用一个区域,触发gc时,遍历当前的使用区域,将当前区域中使用的对象复制到另外一个区域中。
缺点:需要2倍的内存空间
4.标记-整理
原理:该算法结合了复制和标记-清除的优点。
12.Java.lang.Runtime采用的什么样的设计模式?
答:单例
13.jdk动态代理的实现原理
14.servlet的执行流程
(1).客户端发起请求(第一次)
(2).解析请求信息(如:上下文路径和资源文件)
(3).根据上下文路径,去Tomcat的根/config/service.xml文件中,获取所有的<Context/>元素.
(4).在判断是哪一个<Context/>的path的属性值为(上下文路径),接着找到当前的<Context/>元素的dataBase属性值,该属性是当前项目访问的根路径
(5).在从当前项目的根路径下的WEB-INF,目录中,读取web.xml的<servlet>的配置.
(6).获取web.xml中的所有的<url-pattern>元素,判断是否存在当前的访问路径如:/hello
(7).根据当前访问的路径的资源名称,获取对应的servlet的类的全限定名,并放入缓存池中
如不是第一次访问,前面步骤相同.
(8).从Tomcat中的servlet实例缓存池中取出全限定名
(9).创建request,resp对象,在使用servlet的对象调用service方法
(10).在service方法中对客户端做出相应
至于算法我在面试中没有被问到,但在笔试中遇到,常见把二分法和快速查找、冒泡算法了解下即可
所有的都在这里了,建议大家把并发编程和微服务这一块好好看看,至于答案我这里的不是标准,只是自己的看法,当然还有取经的。