Java编程能力测试-我的回答

[复制链接]
lulu188 发表于 2019-3-8 05:30:28 [显示全部楼层] 回帖奖励 倒序浏览 阅读模式 关闭右栏 0 12318
作为一个好几年没翻开IDE的人来填下自己挖的坑,回答下上篇文章的题目,这应当也算能充实说明一旦实在的把握了,实在是很难忘的,固然,另一方面孔似也说明这些年了Java说话层面进步是有限的。

这些题目我是完全按照Java编程进阶的思绪来设想的,很多同学能够感觉背背答案就能去应对一些口试,先不说为什么这个是很难靠背的,究竟上只要口试官稍有点水平,凡是在题目标问法上就会有很多的变化,很轻易判定出口试者的情况,而且口试官应当是按照口试者自己的布景来问题目,而不是陈旧见解,所以我感觉发这些题目,最希望的是大师可以认真的去进修和把握背后的常识点,这样才能以稳定应万变。

    基于BIO实现的Server端,当建立了100个毗连时,会有几多个线程?假如基于NIO,又会是几多个线程? 为什么? 答:BIO由于不是NIO那样的事务机制,在毗连的IO读取上,不管能否真的有读/写发生,都需要阻塞住当前的线程,对于基于BIO实现的Server端,凡是的实现方式都是用一个线程去accept毗连,当毗连建立后,将这个毗连的IO读写放到一个专门的处置线程,所以当建立100个毗连时,凡是会发生1个Accept线程 + 100个处置线程。 NIO经过事务来触发,这样便可以实现在有需要读/写的时辰才处置,不用阻塞当火线程,NIO在处置IO的读写时,当从网卡缓冲区读或写入缓冲区时,这个进程是串行的,所以用太多线程处置IO事务实在也没什么意义,毗连事务由于凡是处置比力快,用1个线程去向置便可以,IO事务呢,凡是会采用cpu core数+1或cpu core数 * 2,这个的缘由是IO线程凡是除了从缓冲区读写外,还会做些比力轻量的例如剖析协议甲等,这些是可以并发的,为什么不但用1个线程处置,是由于当并发的IO事务很是多时,1个线程的效力不敷以发挥出多core的CPU的才能,从而致使这个地方成为瓶颈,这类在散布式cache范例的场景里会比力明显,依照这个,也就更轻易了解为什么在基于Netty等写法式时,不要在IO线程里间接做过量行动,而应当把这些行动转移到别的的线程池里去向置,就是为了能连结好IO事务能被高效处置。 从上面可以看出,对于大大都需要建立大量毗连,但并发读写并不会同时的场景而言,NIO的上风是很是明显的。 这类关于BIO、NIO的问法的变化空间是很是大的,还可以进一步拓展问问AIO和BIO、NIO的底子分歧。凡是来说基于NIO实现的Server端,会用几多个线程去向置IO事务,为什么? 答:见1里面的回答。一个典型的客户端集群->LB->办事端集群这样的结构中,如客户端采用毗连池,长毗连的方式,这类设想你感觉能够会出现什么题目?假如客户端采用的是单个长毗连的方式呢?倘使有题目,你感觉应当怎样处理? 答:这题比力开放,会有各类回答,这里讲下昔时我自己在这里碰到的一个很大的坑,血泪经验,也是我以为这样的结构里最大的风险。 客户端采用毗连池,长毗连,经过LB去毗连后真个办事端集群,在这样的结构下,由于客户端看到的实在只要LB供给出来的vip,会致使的一个严重题目是办事端集群出现不平衡的现象,特别是在办事端集群公布重启等情况下,最卑劣的情况下搞欠好会致使办事端集群压根就没法启动了。 客户端采用单个长毗连,实在也会碰到一样的题目。 昔时,最早的时辰我们的系统就是采用这样的方式,致使出现过严重故障,办事端公布的时辰启动不了,由于公布的分批致使了压力压在了少数的机械上,容量不够就崩了,那次处置的时辰只好先把vip disable掉,办事端集群全数公布好了,再把vip enable,才委曲扛曩昔了。 像这类题目,处理起来很麻烦,例如让长毗连到达一定条件下就断开下,但这样长毗连的感化就下降了,比力底子的处理方式是在这样的场景里把中心的LB去掉,换成类似经过办事注册/发现的机制来处理。 有些同学回答风险是LB的毗连会爆掉,这个大师能够小视了LB装备的才能,在一定例模的场景下是完全没题目标,究竟到达阿里这样范围的企业也很少。CGLIB和Java的静态代理相比,具体有什么分歧? 答:我自己也不是很懂,简单点讲是CGLIB可以代理类,这很是有助于像Spring AOP增强这样的场景的实现。在基于Netty实现FrameDecoder时,下面两种代码的表示会有什么分歧? 第一种 private void callDecode(...) { List<Object> results = new ArrayList<Object>(); while (cumulation.readable()) { int oldReaderIndex = cumulation.readerIndex(); Object frame = decode(context, channel, cumulation); if (frame == null) { if (oldReaderIndex == cumulation.readerIndex()) break; else continue; } else if (oldReaderIndex == cumulation.readerIndex()) { throw new IllegalStateException( "....."); } results.add(frame); } if(results.size() > 0) fireMessageReceived(context, remoteAddress, results); } 第二种 private void callDecode(...) { int oldReaderIndex = cumulation.readerIndex(); Object frame = decode(context, channel, cumulation); if (frame != null) fireMessageReceived(context, remoteAddress, frame); } 答:第一种在并发量很是大时会有很大的上风,缘由是当并发量很是大时,一次流事务里能够带了多个可处置的工具,之前也说了凡是来说基于NIO的模子都是IO线程池 + 营业处置线程池的形式,怎样充实的让IO线程加倍高效的并发决议了server的处置才能,第一种的处置方式可以有用削减IO线程池和营业处置线程池的高低文切换,从而进步IO线程的处置效力。用Executors.newCachedThreadPool建立的线程池,在运转的进程中有能够发生的风险是? 答:这题比力简单,主如果在考查对自带的这些线程池API的把握才能,有没有在用的时辰仔细的去领会,newCachedThreadPool最大的风险就是能够会建立超多的线程,致使最初不能建立线程。 这道题稍微拓展开下可以顺带问问建立100个线程会花费几多资本,一个Java进程能建立几多线程池是受什么限制?new ThreadPoolExecutor(10,100,10,TimeUnit.MILLISECONDS,new LinkedBlockingQueue(10));一个这样建立的线程池,当已经有10个使命在运转时,第11个使命提交到此线程池履行的时辰会发生什么,为什么? 答:之所以问这个题,是我自己之前刚学ThreadPoolExecutor的时辰就进了这个坑,一般逻辑似乎会感觉是当线程数还没到达max,就应当一向建立线程来处置并发的使命,但究竟上ThreadPoolExecutor的实现却是当coreSize满了后,会先往Queue里面塞,只要Queue塞满了,max又还没到,才会去建立线程来处置,所以这道题当第11个使命提交时,会放到Queue里,所以对于用到的API,万万别自以为然,还是去翻翻它具体的实现比力好。 这道题拓展的更难一点可所以问问假如来设想一个类似ThreadPoolExecutor的类,大要怎样设想?实现一个自界说的ThreadFactory的感化凡是是? 答:凡是的感化是给线程取名字,便于今后查题目,很多查过题目标同学应当城市发现,看到jstack出来后一堆看不著名字意义的线程是何等的解体。除了用Object.wait和Object.notifyAll来实现线程间的交互外,你还会常用哪些来实现? 答:这题首要看对线程交互的把握水平,方式很是的多,j.u.c里的非论是BlockingQueue的实现,还是各类类似CountDownLatch、CyclicBarrier,都可以用来实现线程的交互。为什么ConcurrentHashMap可以在高并发的情况下比HashMap更加高效? 答:主如果ConcurrentHashMap在实现时采用的拆分锁,以及奇妙的利用final、volatile,网上有很多相关的解读的文章,这里就不展开了。AtomicInteger、AtomicBoolean这些类之所以在高并发时高效,配合的缘由是? 答:CAS,CAS是硬件级的原语,可以借助此实现Lock-free算法,网上解读的文章一样很是的多,这里也不展开了。请公道的利用Queue来实现一个高并发的生产/消耗的场景,给些焦点的代码片断。 答:这道题主如果想看看对于各类Queue实现的把握情况,例如凡是能够会借助LinkedBlockingQueue来实现简单的生产/消耗,那末像ArrayBlockingQueue、LinkedBlockingQueue的区分是什么,大概你自己实现一个Queue你会怎样做?请实现让10个使命同时并发启动,给些代码片断。 答:借助CyclicBarrier实现,之所以让给代码片断,是看对代码的熟练水平,写代码写的多的话,是完全可以做得手写一段简单的编译不会出错,可运转的代码的。 一样,这类题目可以进一步的问,CyclicBarrier是怎样实现的。在Java法式运转阶段,可以用什么号令行工具来检察当前Java法式的一些启动参数值,例如Heap Size等。 答:jinfo -flags,这个主如果看对Java一些查题目标工具的把握情况,此外能做到类似结果的工具实在也都ok的。用什么号令行工具可以检察运转的Java法式的GC状态,请具体写出号令行格式。 答:凡是可以用jstat -gcutil [pid] [频次,例如几多毫秒一次] [几多次]来看今朝的gc情况,假如已经翻开了gc log,可以间接检察gc日志。 这类题目,稍微拓展下便可以看gc log凡是怎样翻开,具体的号令行参数,一段gc log的解读等。用什么工具,可以在Java法式运转的情况下跟踪某个方式的履行时候,请求参数信息等,并请诠释下工具实现的道理。 答:btrace,Arthas,首要借助JVM attach agent,ASM以及Instrumentation来静态的替换字节码,从而实现静态的对法式运转情况的跟踪。 这题拓展开,可以问会有什么限制,这个可以进一步领会对道理的把握水平,也可以请现实的讲一个借助这些工具排查的case,来看看理论情况。当一个Java法式接收请求,很长时候都没响应的话,凡是你会怎样去排查这类题目? 答:这题很是开放,缘由会很多,凡是来说,需要先确认下请求能否是已经过来了,假如确认请求过来了的话,需要梳理下Java法式接收请求的处置进程,然后jstack看看对应的线程池的情况,看看能否是哪个环节卡住了。 一样,这类题展开的问法就是问讲一个现实的case。Java进程忽然消失了,你会怎样去排查这类题目? 答:这题也很是开放,凡是来说,先去看看java进程的日志,例若有没有hs_err_[pid].log,倘使有,看看日志里的内容,响应的来处置;别的可以看看有没有core dump,倘使有,用gdb查检察;还可以用dmesg,看看能否是什么缘由被os kill了;还有看运维系统的一些操纵日志。 一样,这类题展开的问法就是问讲一个现实的case。以下这段代码思绪,你感觉在运转时能够会发生的风险是,应当若何改良? public List<User> getUsers(String[] userIds){ // 从数据库查找合适userIds的user记录 // 将返回的记录组装为User工具,放入List并返回 } 答:很多同学答复了各类风险,挺好的,我自己回答的话,这题最大的风险是没有限制userIds的个数,能够会致使从数据库里查找大量的数据,并拼装为User工具,一方面能够会使得数据库扛不住,另一方面也有能够致使Java这边OOM了,类似的这样的代码已经致使过很是严重的故障。 之所以问这个题目,是想提醒大师在写代码的进程中要比力好的停止防御性编程。以下两种代码,在运转时有什么分歧?为什么? 第一种 private static final boolean isLoggerDebugEnabled = log.isDebugEnabled(); public void xx(User user){ if(isLoggerDebugEnabled){ log.debug("enter xx method, user id is: " + user.getId()); } } 第二种 public void xx(User user){ log.debug("enter xx method, user id is: " + user.getId()); } 答:假如log的debug级别没开,第一种不会出现字符串拼接,第二种会出现,形成一些young区的内存浪费,所以第一种写法是加倍好的,缘由是第一种在Java运转时的编译进程中会间接优化掉,整段代码会完全拿掉。 这题可以拓展开的问问会有哪些编译的优化技能。Java法式为什么凡是在刚启动的时辰会履行的比力慢,而处置了一些请求后会变快,AOT能带来什么帮助? 答:由于刚启动的时辰Java还处于诠释履行阶段,处置了一些请求后随着C1、C2编译的介入,会优化为机械码,而且借助各类运转时数据的高级优化(例如上面20题的那种),使得Java法式逐步进入一个高速运转的状态,这也是Java这门说话很大的上风,使得法式员间的差异一定水平缩小了,以及不会出现太烂的Java法式。 AOT带来的帮助是在启动前就将一些代码间接编译为机械码,从而在启动瞬间便可以间接跳过诠释履行,进入比力高效的履行。 这个话题确切有点大,前面我约请下专业的JVM同学来写一篇,顺带给大师讲讲阿里的场景里是怎样尽能够去处理启动瞬间慢的这个题目标,包括大师也可以去领会下Azul的ReadyNow!,阿里提的JEP JWarmup。Parallel GC、CMS GC、ZGC、Azul Pauseless GC最首要的分歧是?背后的道理也请简单描写下? 答:这题比上题还大,先简单回答下,前面专题来写吧。 Parallel GC的Young区采用的是Mark-Copy算法,Old区采用的是Mark-Sweep-Compact来实现,Parallel履行,所以决议了Parallel GC在履行YGC、FGC时城市Stop-The-World,但完成GC的速度也会比力快。 CMS GC的Young区采用的也是Mark-Copy,Old区采用的是Concurrent Mark-Sweep,所以决议了CMS GC在对old区接管时酿成的STW时候会更短,避免对利用发生太大的时延影响。 G1 GC采用了Garbage First算法,比力复杂,实现的好呢,理论上是会比CMS GC可以更高效,同时对利用的影响也很小。 ZGC、Azul Pauseless GC采用的算法很纷歧样,特别是Pauseless GC,其中的很重要的一个技能是经过增加Read Barrier来更好的识别对GC而言最关键的references变化的情况。 这题总的来说偏向于去问对GC很是熟的同学,这类题目拓展是很是大的,一方面可所以算法,另一方面可所以更具体的实现,例如GC是怎样实现STW的。请写一段法式,让其运转时的表示为触发5次ygc,然后3次fgc,然后3次ygc,然后1次fgc,请给出代码以及启动参数。 答:这个我不写了,很早之前的文章里似乎也有写过,需要基于对Java内存治理的分代、GC触发机制来设想响应的代码,这类题目变化就更多样了,一方面可以调剂gc的触发形式,另一方面可以经过调剂启动参数,gc的形式,来看能否是真的完全把握gc的常识点。Go的Coroutine和Java的线程机制最首要的分歧是?假如Java说话要通明的实现Coroutine,你感觉首要的难点是? 答:这题也很大,先简单回答,前面专题写。 Java的线程机制首要还是基于Native Thread,Go的Coroutine是进程里自己治理的一种"Thread",所以在高并发的场景下,Coroutine可以有用的下降比力重的native的线程高低文切换,从而来进步并发处置才能。 但今朝很多的Java版本的Coroutine实现都不是很通明,很是多的限制,致使Java很难用上,比力难的是Java里有很多类似synchronized、各类锁、BIO等形成Native Thread间接block住的地方,怎样让这些地方在Coroutine情况里也通明的不block native thread,是关键题目,感爱好的大师可以关注下Openjdk的Project Loom,以及阿里的AJDK Coroutine Wisp。
聊聊系统设想,
温馨提示:
好向圈www.kuaixunai.com是各行业经验分享交流社区,你可以在这里发布交流经验,也可以发布需求与服务,经验圈子里面禁止带推广链接、联系方式、违法词等,违规将封禁账号,相关产品信息将永久不予以通过,同时有需要可以发布在自己的免费建站官网里面或者广告圈, 下载好向圈APP可以加入各行业交流群 本文不代表好向圈的观点和立场,如有侵权请下载好向圈APP联系在线客服进行核实处理。
审核说明:好向圈社区鼓励原创内容发布,如果有从别的地方拷贝复制将不予以通过,原创优质内容搜索引擎会100%收录,运营人员将严格按照上述情况进行审核,望告知!
回复

使用道具 举报

没找到任何评论,期待你打破沉寂

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

24小时热文