触控|疫情稳定,想跳槽的同事被几个面试题,阻挡在了京东的门外

文章图片
最近疫情稳定了 , 跳槽的换工作这块 , 又开始了 , 这不 , 公司的同事因为公司不涨工资的事情 , 已经开始踏上了重新面试 , 寻找更高级别的出路了 , 而前几天的面试 , 让他一次大好的机会被京东的线程面试题阻挡在了门外 。
1.最基础的面试题多线程 , 说实话 , 在大公司对多线程和JVM优化这些内容 , 都是非常看重的 , 因为一些大型的互联网公司不缺少写 CRUD 的初级工程师 , 而缺少的是那些对项目能够进行优化 , 并且对 CRUD 和系统能够做出优化的工程师 , 所以在大公司面试的时候 , 很少有会去问那些比较简单的 , 而且大家都会的面试题的 , 比如:
- 线程的创建方式?
- 实现多线程的方式?好像和上面是一个答案哈 , 但是不影响 , 问法不同 , 回答一样 。
- 在 Java 中 , 如何跳出当前的多重嵌套循环?
- String和StringBuffer、StringBuilder的区别是什么?String为什么是不可变的?
2.进阶面试题而再往后就是真的开始进阶面试题了 , 而阿粉的同事也是因为这些进阶的面试题 , 被京东拒之门外了 , 那么笔者就来带大家看看到底是什么样子的面试题 , 会让同事被如此的“摧残” 。
2.1面试官第一问面试官:你了解IO流么?
在笔者的印象中 , 一般面试大厂都有一个很经典的套路 , 那就是一个知识点 , 问到你回答不上来为止 , 而像百度 , 阿里 , 腾讯这些大厂很多刚开始问得问题都是非常的基础 , 但是接下来 , 分分钟让你在一个问题上自闭 。
IO流?了解呀 , Java中的流 , 可以从不同的角度进行分类 。 按照数据流的方向不同可以分为:输入流和输出流 。 按照处理数据单位不同可以分为:字节流和字符流 。
- 字节流:一次读入或读出是8位二进制 。
- 字符流:一次读入或读出是16位二进制 。
然后分别在说一下都有哪些类一般这个问题就已经算是回答完成了 。
- FileInputStream(字节输入流) , FileOutputStream(字节输出流) , FileReader(字符输入流) , FileWriter(字符输出流)
这问题问出来 , 感觉要和第一个问题差不多是不是 , 而后面面试官的一句话再次出口 ,
- 字节流和字符流哪个好?怎么选择?为什么这么选择?
那么怎么去选择?为什么选择?这种时候就是比较区分看业务情况了 , 因为字符流是对字节流的包装 , 而我们的操作如果需要频繁的使用 IO 来处理字符串 , 那么我们一般通常使用字符流来进行 , 比如读写个 txt 的文档之类的 , 因为字符流具备缓冲区 , 能提高我们的工作性能 , 而如果是操作磁盘文件 , 比如说图片的时候 , 我们都是使用字节流的 , 这些是需要根据实际业务场景进行区分和使用的 。
【触控|疫情稳定,想跳槽的同事被几个面试题,阻挡在了京东的门外】回答完这些之后 , 同事很庆幸 , 当时感觉自己这个问题应该回答的还不错的时候 , 面试官接下来的操作 , 让同事又一次陷入了难受的境地 。 殊不知这是一环套一环 , 环环相扣 , 让你自闭 。
2.3 面试官第三问面试官:你既然了解 IO, 那你对 IO 模型肯定也有所了解 , 那你说说你对 IO 模型理解的部分吧 。
这句话同事在给我说的时候 , 我第一反应就是同事这个问题 , 可能回答的会不太好 , 接下来的坑自己可能要跳下去了 , 因为 IO 模型 , 这块的内容 , 讲解起来有时候会用很长很长的时间 , 对于理解的人 , 可能简短的几句话就能把这些模型讲清楚 , 对于不理解的人 , 可能只能是死记硬背来给面试官复述 。
IO 模型:
阻塞 IO 模型
阻塞 IO 模型是最经典的一种 , 其实说白了就是在我们进行数据读写的时候 , 会出现阻塞的情况 , 当用户线程发出 IO 请求之后 , 内核会去查看数据是否就绪 , 如果没有就绪就会等待数据就绪 , 而用户线程就会处于阻塞状态 , 用户线程交出 CPU 。 其实如果这么解释的话 , 不是很形象 , 我之前看过一个网友说的烧水的案例 , 非常的给力 , 这个小情景是这样的 , 在很久之前 , 电热水壶还没有普及的时候 , 那是后烧水不都是放在火上 , 等水烧开嘛 , 而阻塞就相当于 , 你把水放到煤气灶上烧着 , 然后你就再旁边看着 , 这时候你只能坐在水壶前面等 , 你什么的事情都做不了 , 这时候就和现在是一个状态 , 属于阻塞的状态 , 如果这么理解的话 , 这个阻塞是不是就很好理解了 。
非阻塞 IO 模型
来自百度
当用户线程发起一个read操作后 , 并不需要等待 , 而是马上就得到了一个结果 。 如果结果是一个error时 , 它就知道数据还没有准备好 , 于是它可以再次发送read操作 。 一旦内核中的数据准备好了 , 并且又再次收到了用户线程的请求 , 那么它马上就将数据拷贝到了用户线程 , 然后返回 。
所以事实上 , 在非阻塞IO模型中 , 用户线程需要不断地询问内核数据是否就绪 , 也就说非阻塞IO不会交出CPU , 而会一直占用CPU 。 这时候就相当于是有人在不停的问你 , 水烧开了么 , 水烧开了么?水烧开了吗?这直到水烧开 , 也就是直到这个内核数据准备就绪的时候 , 就能够完成读写 。
多路复用 IO 模型
多路复用 IO 说实话 , 一开始的时候看到这个?多路复用 , 哎呦 , 这个词这么高大上?啥是个多路复用 , 但是经过一系列的观察之后 , 很多地方都能通俗的去解释这个多路复用 , 比如说我们家里的电话线 , 你在上网的时候 , 来了个电话 , 你能接吧 , 你接电话的时候还不忘在网上和朋友日常胡吹 , 这情况就可以称之为多路复用 , 那么多路复用IO模型是个什么意思呢?
来自百度的解释是这样说的:I/O是指网络I/O多路指多个TCP连接(即socket或者channel)复用指复用一个或几个线程 。 意思说一个或一组线程处理多个TCP连接 。 最大优势是减少系统开销小 , 不必创建过多的进程/线程 , 也不必维护这些进程/线程 。 IO多路复用使用两个系统调用(select/poll/epoll和recvfrom) , blocking IO只调用了recvfrom;select/poll/epoll 核心是可以同时处理多个connection , 而不是更快 , 所以连接数不高的话 , 性能不一定比多线程+阻塞IO好多路复用模型中 , 每一个socket , 设置为non-blocking阻塞是被select这个函数block , 而不是被socket阻塞的 。
而我们从中摘取出我们所需要的关键的信息 , 比如说一个或一组线程处理多个TCP连接 , 而在当你说出这个多路复用的时候 , 你就会被面试官记下来 , 如果你能把多路复用这个IO模型讲清楚 , 那么你就对 Java 中的 NIO有所了解了 , 而关于这个 多路复用这块内容 , 之前的文章也有讲解
深度探测 java IO
在这篇文章中有你想要的答案呦 。 在这里就不在给大家讲解了 , 等你看完 , 绝对有所收获 。 而我的同事就是因为这里 , 回答的并不好 , 给了面试官非常不好的感受 , 这才第几步就已经不行了?
其实说到这些的时候 , 一般的面试官很容易就让你停下来了 , 因为 IO 流虽然在我们日常操作里面经常的用 , 但是很多人接触的并不是特别的深刻 , 所以如果你在这里说的不太满意的话 , 那么面试官估计也就没有兴趣听下去了 , 但是我还是要讲下去的 。
异步 IO 模型
其实异步 IO 模型 , 这个烧水的案例解释的那叫一个清晰透彻 , 你把水壶放在了这个煤气灶上 , 然后你想起来 , 呀 , 还有代码没写完 , 然后你就直接去写代码了 , 而异步 IO 模型是最理想的 IO 模型 , 在异步 IO 模型中 , 当用户线程发起 read 操作之后 , 立刻就可以开始去做其它的事 。 而另一方面 , 从内核的角度 , 当它受到一个 asynchronous read 之后 , 它会立刻返回 , 说明 read 请求已经成功发起了 , 因此不会对用户线程产生任何block 。
而内核会一直等待数据准备完成 , 然后将数据拷贝到用户线程 , 当这一切都完成之后 , 内核会给用户线程发送一个信号 , 告诉它read 操作完成了 。
只需要先发起一个请求 , 当接收内核返回的成功信号时表示 IO 操作已经完成 , 可以直接去使用数据了 。
而需要注意的一点就是异步IO是需要类支持的Asynchronous
2.4面试官第四问在 IO 这块的时候 , 同事回答的如果说是百分之80的话 , 那么在这最后的第四问 , 就是属于压死骆驼的最后一根稻草了 ,
面试官:你对线程池的了解多不多 , 说一下你对线程池的了解吧 , 说实话 , 在听到有这个问题的时候 , 一点都不惊讶 , 毕竟大厂问得最多的就是多线程 , 线程问题一直是属于面试的大厂必问的知识点 , 而这个知识点就是属于看你对线程这块内容的掌握程度了 。
线程池的组成
- 线程池管理器:用于创建并管理线程池
- 工作线程:线程池中的线程
- 任务接口:每个任务必须实现的接口 , 用于工作线程调度其运行
- 任务队列:用于存放待处理的任务 , 提供一种缓冲机制
ThreadPoolExecutor
- corePoolSize:指定了线程池中的线程数量 。
- maximumPoolSize:指定了线程池中的最大线程数量 。
- keepAliveTime:当前线程池数量超过 corePoolSize 时 , 多余的空闲线程的存活时间 , 即多次时间内会被销毁 。
- unit:keepAliveTime 的单位 。
- workQueue:任务队列 , 被提交但尚未被执行的任务 。
- threadFactory:线程工厂 , 用于创建线程 , 一般用默认的即可 。
- handler:拒绝策略 , 当任务太多来不及处理 , 如何拒绝任务 。
线程池做的工作主要是控制运行的线程的数量 , 处理过程中将任务放入队列 , 然后在线程创建后 , 启动这些任务 , 如果线程数量超过了最大数量超出数量的线程排队等候 , 等其它线程执行完毕 , 再从队列中取出任务来执行 。 他的主要特点为:线程复用;控制最大并发数;管理线程 。
他再说完这些的时候 , 面试官感觉可能还行 , 然后继续深挖 , 而接下来的深挖 , 就彻底的被京东给拒之门外了 ,
面试官:你知道什么是拒绝策略么?在面试官的眼中可能会想 , 你上面吧线程池的组成 , 原理都说了 , 拒绝策略应该会吧 , 结果是同事真的没有了解这一块的内容 , 于是回答的是不太了解 , 而这个回答 , 面试官说那好吧 , 那我们今天就先聊到这里吧 。
那么什么是拒绝策略?
拒绝策略
当线程池的任务缓存队列已满并且线程池中的线程数目达到maximumPoolSize时 , 如果还有任务到来就会采取任务拒绝策略 。 也就是说 , 我的等待队列也满了 , 你给我说还有新的活要干 , 不好意思 , 我表示拒绝 , 而 JDK 自带的拒绝策略也是有好几个的 , 分别如下:
- AbortPolicy : 直接抛出异常 , 阻止系统正常运行 。
- CallerRunsPolicy : 只要线程池未关闭 , 该策略直接在调用者线程中 , 运行当前被丢弃的任务 。 显然这样做不会真的丢弃任务 , 但是 , 任务提交线程的性能极有可能会急剧下降 。
- DiscardOldestPolicy : 丢弃最老的一个请求 , 也就是即将被执行的一个任务 , 并尝试再次提交当前任务 。
- DiscardPolicy : 该策略默默地丢弃无法处理的任务 , 不予任何处理 。 如果允许任务丢失 , 这是最好的一种方案 。
关于拒绝策略 , 我会在之后的文章给大家在详细的讲讲这个里面到底是个什么东西 , 给大家进大厂做一些准备 。
最后笔者这里也是收集整理了一些面试资料准备分享给粉丝朋友们 , 希望能起一些参考作用 。 有想获取的粉丝朋友:关注后 , 后台私信回复“666”就可以了
推荐阅读
- 一降一升电网销分化明显 疫情催生保险网销新模式
- 健康广东|8月18日广东疫情最新通报:广州深圳新增多少病例
- 陕西卫健委|8月18日陕西疫情最新通报:新增2例境外输入确诊病例
- 挺过上半年疫情冲击,中国电竞行业为啥更红火了?
- 新冠肺炎疫情|国家卫健委:17日新增确诊病例22例,均为境外输入
- FINA游泳世界杯因疫情推迟,济南站2021年9月举办
- 疫情|警惕!全球新冠累计超2199万例 欧洲疫情全面反弹
- 疫情大冲击下,美政客作出重大误判,基辛格向全球发出警告
- 推荐|疫情报告:31省区市新增22例均为境外输入,北京连续11天零新增
- 新华网|美国邮政局成疫情期大选风暴眼
