这里有一份面筋请查收(七)

本篇所要介绍的是一家互联网企业,简称MD好了。一面是电面,二三面是face2face的技术面,4面是HR面。


一面

一面的具体内容忘了记录了,大概面了45mins,问了30mins的NIO。
这里就来讲一讲NIO的一些知识点。NIO有三个部分:Selector, Channel和Buffer. 传统的IO基于字节流和字符流进行操作。而NIO基于Channel和Buffer(缓冲区)进行操作,数据总是从通道读取到缓冲区,或者从缓冲区写入通道中。Selector用于监听多个通道的时间(比如打开,数据到达),因此,单个线程可以监听多个数据通道。
Selector内部原理实际是在做一个对所注册的Channel的轮询访问,不断的轮询,一旦轮询到一个channel有所注册的事情发生,比如数据来了,他就会站起来报告,交出一把钥匙(SelectionKey),让我妈通过这把钥匙来读取channel的内容。
NIO有一个重要的点是:Reactor模式。从网上抠来一张Reactor模式的模型图如下:

Reactor模式有两大角色:Reactor和Handler. Reactor负责响应I/O事件;Handler负责非阻塞行为。至于Reactor模式的编码风格我就不赘述了。
前面说到了Selector的原理就是轮询,但是Java NIO中有个epoll()(linux系统下),这个对并发idle Connection会有大幅度的性能提升。epoll是linux下多路复用I/O接口Select/poll的增强版本。一般的轮询方式一个进程打开的FD(File Descriptor)是有一定限制的,FD_SETSIZE默认是2048,这个宏定义可以修改,但修改后的效果并不理想,对于那些需要支持上万连接数的IM服务器来说显然太少。epoll没有这个限制,可以通过”cat /proc/sys/fs/file-max”来查看支持的FD上限。博主本地机器是205822。epoll()有两种使用模式:LT(Level triggered)缺省,ET(Edge-triggered)高速。
epoll有一个著名的epoll-bug, 也可能会导致无效的状态的选择和100%的CPU利用率,要解决epoll-bug的唯一方法是回收旧的选择,将先前注册的通道实例转移到新创建的选择器上。当然如果使用一些框架比如:Netty, Mina.
上面的全问到了,问的还挺深的。最后问了为什么没用Netty之类的框架实现,还有有了解过其他的分布式框架么?
还问了一些Java基础题。
比如多线程的ThreadPollExecutor中的饱和策略有哪些?
Ans:当线程池和队列都满了,则表明该线程池已达饱和状态。

  • ThreadPoolExecutor.AbortPolicy:处理程序遭到拒绝,则直接抛出运行时异常 RejectedExecutionException。(默认策略)
  • ThreadPoolExecutor.CallerRunsPolicy:调用者所在线程来运行该任务,此策略提供简单的反馈控制机制,能够减缓新任务的提交速度。
  • ThreadPoolExecutor.DiscardPolicy:无法执行的任务将被删除。
  • ThreadPoolExecutor.DiscardOldestPolicy:如果执行程序尚未关闭,则位于工作队列头部的任务将被删除,然后重新尝试执行任务(如果再次失败,则重复此过程)。

线程池怎么合理配置?
Ans:需要针对具体情况而具体处理,不同的任务类别应采用不同规模的线程池,任务类别可划分为CPU密集型任务、IO密集型任务和混合型任务。

  • 对于CPU密集型任务:线程池中线程个数应尽量少,不应大于CPU核心数;
  • 对于IO密集型任务:由于IO操作速度远低于CPU速度,那么在运行这类任务时,CPU绝大多数时间处于空闲状态,那么线程池可以配置尽量多些的线程,以提高CPU利用率;
  • 对于混合型任务:可以拆分为CPU密集型任务和IO密集型任务,当这两类任务执行时间相差无几时,通过拆分再执行的吞吐率高于串行执行的吞吐率,但若这两类任务执行时间有数据级的差距,那么没有拆分的意义。

线程数的个数?(这个问题二面也问到了)
Nthreads = Ncpu*Ucpu*(1+W/C)。Ncpu是cpu的个数,可以通过Runtime.getRuntime.availableProcessors()获取。Ucpu是cpu的使用率。W/C=Wait-Time/Compute-Time. ps:Runtime.getRuntime是单例模式。


二面

二面先对简历上的内容询问了一番,问了一些问题,再此就不表了,接下去问了些Java类的问题。
1.线程池ThreadPoolExecutor以及Executors的一些问题。
2.ReentrantLock和synchronized的区别。

  • ReentrantLock可以中断地获取锁(void lockInterruptibly() throws InterruptedException)
  • ReentrantLock可以尝试非阻塞地获取锁(boolean tryLock())
  • ReentrantLock可以超时获取锁。通过tryLock(timeout, unit),可以尝试获得锁,并且指定等待的时间。
  • ReentrantLock可以实现公平锁。通过new ReentrantLock(true)实现。
  • ReentrantLock对象可以同时绑定多个Condition对象,而在synchronized中,锁对象的的wait(), notify(), notifyAll()方法可以实现一个隐含条件,如果要和多于一个的条件关联的对象,就不得不额外地添加一个锁,而ReentrantLock则无需这样做,只需要多次调用newCondition()方法即可。

从上面的比较中可以看出ReentrantLock比synchronized有很多的优点,但是JDK的开发团队还是推崇使用synchronized的方式,在JDK5中ReentrantLock比synchronized的性能优越很多,在JDK6中进行了很多的优化,ReentrantLock比synchronized只是稍微好点,而且ReentrantLock用的不好,比如Lock.lock之后再finally块中忘了Lock.unlock操作锁就永远得不到释放,而synchronized可以自动释放锁。而且经过JDK的开发团队的不懈努力,synchronized的性能会越来越好,比如:偏向锁,轻量级锁,自旋锁,锁粗化以及锁细化等优化操作。

3.ReentrantLock又称之为什么?怎么实现的?还有那些相同的?
ReentrantLock又称之为可重入锁,内部实现是基于AQS的(对于AQS不明白的小伙伴可以度娘了)。还有一些也是基于AQS的比如Semaphore,还有ReentrantReadWriteLock(独占锁+共享锁)。在ReentrantReadWriteLock中又涉及了一个锁降级的概念:先Hold写锁,再获取读锁,再释放写锁。没有锁升级的概念。(有关多线程的知识,可以翻看博主相关的文章,详情见参考资料1-4。)
4.sleep和wait的区别?为什么sleep在Thread中,wait在Object中?
sleep不让出锁,它不会导致锁行为的改变,而wait会让出锁。Thread.sleep的调用不会影响锁的改变,所以放在sleep中,wait与锁有关所以放在Object中。
5.为什么Java中的锁是对象锁而不是线程锁?
这个问题比较抽象,主要是在对象锁的编程模型比较简单,线程锁其实也可以,但是编程模型太复杂,所以Java采用的对象锁。
6. 写一个单例模式。
博主写了一个内部类的单例模式,然后说了其他的写法比如:enum或者synchronized的写法,详情可以关注《设计模式:单例模式(Singleton)》。
后面又问了一个问题:一个类中所有的方法和属性都标注为static的,那么这是一个单例么?面试官的语气暗示这不是一个单例,但的确想不出不是单例的地方,想了一会儿才明白过来这的确是一个单例的写法。单例是保证一个类的实例构造器只实现一次,而全部标注为static的类,它就只有类构造器,类构造器可以由JVM确保只执行一次,而且是线程安全的。
还有一道设计题:微信公众号拉取粉丝数量。


三面

三面的面试官照着简历问了一些问题,然后问了一些其他的和技术无关的,最后还问了一个技术类问题:怎么可以发生Full GC?
Full GC是指老年代发生了Stop the world的操作。详细可以参考《Java堆内存 》。
比如在CMS执行时有初始标记、并发标记、重新标记、并发清除、并发重置5个步骤中,初始标记和重新标记都是stop the world的,当发生Concurrent Mode Failure时,会触发一次Serial-Old的操作。
可以在程序中通过设置-Xmx, -Xms等参数去触发,也可以通过System.gc()触发。当然有两个工具JConsole和JVsualVm中有“GC”的按钮。
(剩下的可以在留言区补充。)


总结:无。(对这家公司太熟悉,不方便评价~~)


更多链接请关注:
这里有一份面筋请查收(一)
这里有一份面筋请查收(二)
这里有一份面筋请查收(三)
这里有一份面筋请查收(四)
这里有一份面筋请查收(五)
这里有一份面筋请查收(六)
这里有一份面筋请查收(七)
这里有一份面筋请查收(八)

参考资料
1. Java多线程知识小抄集(一)
2. Java多线程知识小抄集(二)
3. Java多线程知识小抄集(三)
4. Java多线程知识小抄集(四)
5. 设计模式:单例模式(Singleton)
6. Java堆内存

相关推荐:

5年Android程序员面试字节跳动两轮后被完虐,请查收给你的面试指南

大家应该看过很多分享面试成功的经验,但根据幸存者偏差的理论,也许多看看别人面试失败在哪里,对自己才更有帮助。 最近跟一个朋友聊天,他准备了几个月,刚刚参加完字节跳动面试,第二面结束后,嗯,挂了… 所以啊,不管怎么样,不论是什么样的大小面试,要想不被面试官虐的不要不要的,只有刷爆面试题题做好全面的准备...

一份 Nervos 区块链周的日程安排,请查收!

本周(5月13日-17日),我们迎来了国内外的区块链周。 NervosinNewYork 在国外,纽约区块链周期间,Nervos将参加以下几场活动: 5月13日,「NYCBlockchainDeepTechFiresideChat」,Nervos将和Spacemesh、Kadena、Alacris一...

您收到一份Python入门教程,请查收

不久前得知了“两件大事”(即万矿已加入Wind终端;万矿已开放注册)后,很多朋友踊跃加入了万矿,也有部分小伙伴表示正努力学习Python,希望可以获得一些入门教程。   在此,小编为大家准备了系列入门大餐: 包括: 更多干货分享加python编程语言学习QQ群515267276  Python基本知...

这有一份雪浪大会超全攻略,请查收

           关注ITValue,查看企业级市场最新鲜、最具价值的报道!   “从制造业中来,到制造业中去”   还有1天,期待已久的雪浪大会就如期而至。   如果你是制造业企业,这里肯定能让你心头一动的新模式、新场景;   如果你是金融机构,这里也会有你未来的很多好朋友;   如果你是地方...

Hi,你有一份 TiDB 易用性挑战赛「捞分指南」请查收

TiDB挑战赛第二季之易用性挑战赛已经开始一周了,由于有参加过上一季性能挑战赛的老玩家强势加入,这一季挑战赛的竞争格外激烈,短短一周的时间,已有3支队伍获得了上千积分! 完整积分排行榜可以登陆活动官网查看。 战况简介: BABAIsWatchingYouTeam通过改进Rust-Prometheus...

2.2 这里有一份logistic回归教程,请查收

欢迎分享本文,转载请保留出处 点击关注,获取最新AI干货本节课,我们讲讲logistic回归。这是一个学习算法,用在监督学习问题中。 输出y标签是0或1时,这是一个二元分类问题。 已知的输入特征向量x可能是一张图。你希望把识别出,这是不是猫图。你需要一个算法,可以给出一个预测值。我们说预测值y帽,就...

叮咚! 你有一份节日祝福请查收~

点击上方“Hulu”可以订阅哦! 叮咚~ 在这个平凡又特殊的星期三 有一份来自Hulu官方的节日祝福~ 1024 1024 对于程序员来说 是个十分熟悉又有缘分的数字 在日复一日的工作中 程序员们用最基本的单位和操作 以最低调、最勤奋的方式 搭建起了一个令人惊艳的技术世界 在这个属于你们的节日 想对...

叮!您有一份工作汇报请查收

致每一位LeanCloud伙伴: 春节假期的结束意味着新一年的正式开始。我想总结一下LeanCloud过去一年的进展,以及对2018的计划和展望。 2017年是LeanCloud成立的第四年,我们无论是在商业上还是产品上都取得了不少进步。我们过去连续三年在收入上保持了每年大约一倍的稳定增长。在产品方...