专栏首页美团技术团队【你问我答】你与Java大牛的距离,只差这24个问题

【你问我答】你与Java大牛的距离,只差这24个问题

点击上方“公众号”可以订阅哦

上周我们做了第一期“你问我答”活动,没想到有那么多读者进行了提问,受宠若惊。

问题比较多也比较杂,王锐老师很认真地给出了一些答案,并在美团点评内部的Java俱乐部里做了诸多讨论,同学们也都纷纷加入问答队伍,就自己擅长的领域给出解答,下面我们就来看下他们的回答吧!

1

小超:

请教一个问题,在局域网内对一台灰度机器进行压测,如果带宽被打满后,压测的效果也就到瓶颈了,那么问题来了,怎么判断这台灰度机器的带宽是否被打满? 谢谢哥哥们。

答:

有几个工具都可以看iftop(神器)、dstat、sar都可以看。小贴士,我们常说的网速是按照bit计算的,所以计算流量时注意单位,一般一个千兆网卡,其读或者写达到10M/8 byte时,网卡就已经被打满了。

2

水木曰一:

请问Java有什么方法可以优雅地hook一个第三方库的静态方法吗?

答:

可以使用btrace及相关的衍生工具。

3

惜花朝拾:

对于在Java中使用JNI您是怎么看的?

答:

现在的软件开发已经不是以前那种一门语言扛到底的时代了,软件开发倾向细分工,用最合适的工具做最合适的事。

4

是海彬也是墨黎:

OSGI前路在何方?模块化、热替换的概念前几年一直炒的火热。最近了解了一下,一直想不明白,会有多少人真的敢在生产环境直接做模块的替换,特别是在现在自动化运维比较丰富的情况下,直接整个应用重新部署的工作量越来越小,真的有必要花这么多精力做这个事情?另外,Spring已经在最新版本去掉OSGI,以后该何去何从呢?

答:

以前做过一些OSGI规范实现的事情,看到这个问题不由得兴奋了。单纯从应用角度来说,个人不建议引入OSGI技术,因为这个技术带来的优势远远小于付出的代价。但是,OSGI作为Java世界事实上的标准,在后续的Java 9中有很强的指导意义,深入学习OSGI可以更方便的学习Java 9的模块化。

另外,OSGI可以说是classloader体系的集大成者,有志于学习Java classloader实战的同学,OSGI是一个必修课。夸张一点说,理解了OSGI的整套技术体系,日后再碰到classloader相关问题时会感觉有些爽。

5

陈小白→_→。:

您好,谢谢您能分享。 我想请教一个问题,比如我写了一个小插件(类似fastjson)这种工具类。怎么去判断它性能是不是满足要求呢?看内存堆占用的空间或者还是其它的参考量?谢谢。

答:

每个组件都有其关注的核心目标,如果是一个客户端库,需要考量的点是每次方法调用的执行时间(越高越好)、使用时内存占用(越低越好)和因为本组件引起的GC数(越少越好)。

6

kan:

线上CPU很高、内存占用很少,有能快速查找到原因的方法吗?

答:

给一个代码,在Linux下保存成.sh文件直接执行即可。

#!/bin/sh
ts=$(date +"%s")
jvmPid=$1
defaultLines=100
defaultTop=20

threadStackLines=${2:-$defaultLines}
topThreads=${3:-$defaultTop}

jvmCapture=$(top -b -n1 | grep java )
threadsTopCapture=$(top -b -n1 -H | grep java )
jstackOutput=$(echo "$(jstack $jvmPid )" )
topOutput=$(echo "$(echo "$threadsTopCapture" | head -n $topThreads | perl -pe 's/\e\[?.*?[\@-~] ?//g' | awk '{gsub(/^ +/,"");print}' | awk '{gsub(/ +|[+-]/," ");print}' | cut -d " " -f 1,9 )\n ")

echo "*************************************************************************************************************"

uptime

echo "Analyzing top $topThreads threads"

echo "*************************************************************************************************************"

printf %s "$topOutput" | while IFS= read  line

do
   pid=$(echo $line | cut -d " " -f 1)
   hexapid=$(printf "%x" $pid)
   cpu=$(echo $line | cut -d " " -f 2)
   echo -n $cpu"% [$pid] " 
   echo "$jstackOutput" | grep "tid.*0x$hexapid " -A $threadStackLines | sed -n -e '/0x'$hexapid'/,/tid/ p' | head -n -1
   echo "\n"
done

echo "\n" 

代码的意思,打印出JVM的所有线程以及按照CPU占比排序。

7

Zeng

为什么Java 8重写了ConcurrentHashMap?基于什么的考虑?优化了什么特性?

答:

为了获得更好的性能,1.8的ConcurrentHashMap在原来的基础上性能做了改进:

① table每个元素作为一个桶,锁的粒度更细,用synchronized关键字锁住table[i]。

② 加入红黑树,当链表的数量超过8并且当前capacity大于64时候,将链表转为红黑树,时间复杂度O(N)→O(logN),并且红黑树中利用读写锁保证添加修复和删除修复时候的线程安全。

另外,关于ConcurrentHashMap在1.8中,除了做了扩容时的优化以外,也去除了分段锁,原因是分段锁的在扩充并发度以及整个map容量扩展时需要锁住所有的段。所以,1.8中对ConcurrentHashMap做了更细粒度的优化,只在put、resize以及扩容是加锁,来做优化。也可参考公众号之前发表过的文章《Java 8 之重新认识HashMap》。

8

王志坚 :

如果用微服务思想开发,Dubbo和Spring cloud那个更好。

答:

Dubbo和Spring cloud不是一个层面上,如果要做微服务设计,必然会有系统间交互,RPC是系统间交互的一种,服务治理也是微服务的一个必需子集,但是微服务还包括其它的东西。而Spring Cloud是微服务的一种实现,其包含的功能要多于Dubbo。

9

silencehere:

异地跨数据中心的情况下,常用的分布式协议和系统还能正常工作吗?如何进行改造实现跨数据中心较高网络延时下,消息能快速传递?

答:

分布式协议其实本身就是为了应对多数据中心,因为CAP中的P更多的出现在多数据中心交互中。关于2个数据中心的数据传递基本的思路有2个:一是建设优质的专线,二是变交互数据传输为批量数据传输。

10

306米的天空:

您好,想问一个JVM比较基础的知识,现在的垃圾收集都是分代回收,那么在回收新生代的时候是要同时扫描老年代吗?是全表还是有一种策略,比如G1的Remembered set,这个set只是记录了一种引用关系;那其它的分代回收,比如CMS和ParNew组合时只能是回收新生代的时候扫描老年代吗?那这样效率不就是降低了不少吗?

答:

对于老年代指向新生代的引用,JVM提供了一种叫card table的数据结构,所以每次并不需要全量遍历老年代,只需要遍历card table就行了。

11

春雷:

Java为啥不能继承多个父类,这么设计有啥优点,写程序时遇到需要多继承了该怎么解决?

答:

多重继承一般会引入很多麻烦,比如类关系复杂、层级过长等,一般语言中都是使用受限制的多重继承。对比多种语言来看,Java是implement多个接口,这种可以认为是继承规范(定义),然后会用组合模式来完成类似多重继承。Python是mixin继承模式,是代码继承(有一定要求),详细对比建议Google或者知乎了解下mixin、MRO Python,多重继承这几个关键词。

12

kan:

线上定位内存JVM内存溢出,除了打印堆栈拿出来分析,还有没有其它的方式?

答:

导出JVM dump文件,在本地使用Eclipse插件MAT分析,可视化的分析最方便、直观、有效。

13

十夕之寸:

ThreadLocal在使用上有什么需要注意的?在高并发请求的环境下性能如何?会有什么问题?

答:

① 注意事项:使用结束以后进行remove操作,避免ThreadLocal对象越来越大。

② 高并发的场景:由于ThreadLocal内部使用HashMap的原理,key=currentThread,因为HashMap是非线程安全的,一定要注意hashmap.resize的时候,可能会导致某几个CPU 100%的问题,进而导致应用出现资源耗尽等不可预知的问题。

14

不要@我:

目前工作三年的Java,想做到技术专家应该具备什么样的能力?

答:

① 编码实践,例如坚持在GitHub上写一些为了应用技术而应用的example。

② 读他人代码,各种开源框架的源码。

③ 多读书,多看Importnew、InfoQ之类的文章,多问,看到相似点时回过去看看自己做的是否还有改进的空间。

15

盼 零点:

克隆对象时,为什么要在对象中重写一个public类型的clone()方法呢? 我知道Object类中有一个protected类型的clone()方法,但是要克隆的对象是Object类的子类啊,在不同包下并存在继承关系的条件下应该可以访问Object的protected方法啊?

答:

首先Java的clone是设计模式中原型模式的一个典型应用,克隆分浅拷贝和深拷贝,二者的区别自行搜索。Object.clone()是浅拷贝,一般复杂对象的clone最好使用深拷贝,所以需要重写clone方法。

16

小超:

您好,我想请问下,JVM(基于JDK 1.8)在执行垃圾回收的时候,对于堆区年轻代内存区域回收较频繁,请问如何更好的控制JVM执行回收的节奏? 另外,如果合理地控制好年轻代和年老代的占比以及年轻代里面的eden区和两个幸存区的占比,能很好的达到垃圾回收效果,请问下,如何合理的控制堆区的年老代和年轻代的内存分配占比?还有如何更好地控制年轻代中,eden区和两个幸存区的占比? 不知道我有没有表达清楚,哈哈,请大神指导。

答:

年轻代大小选择

① 响应时间优先的应用:尽可能设置大,直到接近系统的最低响应时间限制(根据实际情况选择)。在此种情况下,年轻代收集发生的频率也是最小的。同时,减少到达年老代的对象。

② 吞吐量优先的应用:尽可能设置大,可能到达Gbit的程度。因为对响应时间没有要求,垃圾收集可以并行进行,一般适合8 CPU以上的应用。

年老代大小选择

① 响应时间优先的应用:年老代使用并发收集器,所以其大小需要小心设置,一般要考虑并发会话率和会话持续时间等一些参数。如果堆设置小了,可以会造成内存碎片、高回收频率以及应用暂停而使用传统的标记清除方式;如果堆大了,则需要较长的收集时间。最优化的方案,一般需要参考以下数据获得:

1. 并发垃圾收集信息

2. 持久代并发收集次数

3. 传统GC信息

4. 花在年轻代和年老代回收上的时间比例

减少年轻代和年老代花费的时间,一般会提高应用的效率

17

holy4god:

如何避开泛型类型擦除带来的限制?

答:

个人觉得换个不会泛型擦除的语言,如 C#,要不换其他弱类型语言或者Kotlin这种,可以编译期推导出类型的语言。Java的话只能开发时多注意了。

另外感觉问题还是缺少一些上下文,猜大概是问这个吧?

public static void main(String[] args) {
   List<Integer> intList = new ArrayList<>();
   intList.add(1);

   try {
       Method method = intList.getClass().getDeclaredMethod("add", Object.class);

       try {
           method.invoke(intList, "string1");
           method.invoke(intList, 0.5f);
       } catch (IllegalAccessException e) {
           e.printStackTrace();
       } catch (InvocationTargetException e) {
           e.printStackTrace();
       }
   } catch (NoSuchMethodException e) {
       e.printStackTrace();
   }
   for (Object i : intList) {
       System.out.println(i.toString());
   }
}

18

The light:

JVM如何进阶,目前周志明的《深入理解JVM》第2版看了两遍,能够根据目录口述书中大部分内容,还需要了解哪些知识?

答:

周志明的书只能算是JVM的入门书籍。接下来你应该去读一读《Java虚拟机规范》,周志明的书很多内容是从里面来的,但是规范本身比较详细,注意读英文原版。

其次去读一下Oralce的文档:《Hotspot Memory Management white paper》, 《Java Platform, Standard Edition HotSpot Virtual Machine Garbage Collection Tuning Guide》。

现在你需要进一步修炼关于内存管理的部分,阅读比如《垃圾回收算法与实现》,如果这本读完还不满足,那么阅读《自动内存管理艺术——垃圾回收算法手册》。到了这一步,理论你已经掌握得很好了,是时候把Hotspot源码download下来编译好之后断点调试玩玩了,这个时候我要推荐你今年阿里人刚出的《揭秘Java虚拟机》,不过阅读这本书之前你要是愿意先读完《深入理解计算机系统》效果更好。到了这一步,剩下的,自己探索了,我也在探索。

19

阿龙

如何更好的使用多线程?

答:

① 高并发、任务执行时间短的业务,线程池线程数可以设置为CPU核数+1,减少线程上下文的切换。

② 并发不高、任务执行时间长的业务要区分开看:  

  • 假如是业务时间长集中在I/O操作上,也就是I/O密集型的任务,因为I/O操作并不占用CPU,所以不要让所有的CPU闲下来,可以加大线程池中的线程数目,让CPU处理更多的业务。  
  • 假如是业务时间长集中在计算操作上,也就是计算密集型任务,这个就没办法了,和①一样吧,线程池中的线程数设置得少一些,减少线程上下文的切换。

③ 并发高、业务执行时间长,解决这种类型任务的关键不在于线程池而在于整体架构的设计,看看这些业务里面某些数据是否能做缓存是第一步,增加服务器是第二步,至于线程池的设置,设置参考②。

最后,业务执行时间长的问题,也可能需要分析一下,看看能不能使用中间件对任务进行拆分和解耦。

20

Pielo:

能请问Java阻塞锁中偏向锁转为轻量级锁的具体条件么?我在网上搜索到的和书上看到的大多是一笔略过了。

答:

升级的代码可以在biasedLock.cpp(openjdk1.8)里的:

if (highest_lock != NULL) {
    // Fix up highest lock to contain displaced header and point
    // object at it
    highest_lock->set_displaced_header(unbiased_prototype);
    // Reset object header to point to displaced mark
    obj->set_mark(markOopDesc::encode(highest_lock));
    assert(!obj->mark()->has_bias_pattern(), "illegal mark state: stack lock used bias bit");
    if (TraceBiasedLocking && (Verbose || !is_bulk)) {
      tty->print_cr("  Revoked bias of currently-locked object");
    }
  }

附上(我理解的)偏向锁升级的流程图:

21

伊诺

在实际运用中如何清晰明了地观察JVM的运用过程?

答:

图形工具JProfiler、JConsole、Java VisualVM,命令jps、jstack、jmap、jhat、jstat

22

问: 数据库更新时候会有失败情况,一般修复数据需要怎么操作?

答:

补偿和重试。

23

土豆牛肉秋刀鱼:

使用Spring data JPA时,是直接序列化entity,还是再写一个dto,存入ID加上一些冗余的用户信息来的好,各有什么优缺点?

麻烦了~

答:

企业设计模式中有一个Active Record,你可以看一下。

24

曹振:

美团在分布式事物方面是怎么做的?有没有排查JVM内存溢出或者崩溃的案例分享?消息队列满了怎么处理的?美团秒杀方面的分享?

答:

金融平台的技术团队有一个分布式事务系统设计,来美团点评之后你就可以看到它。dump它,使用JXXXX工具分析,增加更多消费者。这个难到我了。

本文分享自微信公众号 - 美团点评技术团队(meituantech),作者:美团点评技术学院

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2017-08-25

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Linux与JVM的内存关系分析

    引言 在一些物理内存为8g的服务器上,主要运行一个Java服务,系统内存分配如下:Java服务的JVM堆大小设置为6g,一个监控进程占用大约600m,Linux...

    美团技术团队
  • 美团点评数据库高可用架构的演进与设想

    本文介绍最近几年美团点评MySQL数据库高可用架构的演进过程,以及我们在开源技术基础上做的一些创新。同时,也和业界其它方案进行综合对比,了解业界在高可用方面的进...

    美团技术团队
  • 美团 R 语言数据运营实战

    近年来,随着分布式数据处理技术的不断革新,Hive、Spark、Kylin、Impala、Presto 等工具不断推陈出新,对大数据集合的计算和存储成为现实,数...

    美团技术团队
  • Java面试- JVM 内存模型讲解

    经常有人会有这么一个疑惑,难道 Java 开发就一定要懂得 JVM 的原理吗?我不懂 JVM ,但我照样可以开发。确实,但如果懂得了 JVM ,可以让你在技术的...

    健程之道
  • Java研发方向如何准备BAT技术面试答案(上)

    最近因为忙于工作,没时间整理,本篇是下班后晚上抽空整理的,文中部分答案本来是想自己好好整理一份的,但是时间真的很紧,所以就整理了一下网络上的文章链接,挑了写的不...

    JavaQ
  • Bash概论 - Linux系列教程补充篇

    本篇是我最开始学习Linux命令时看的一篇帖子,最早见于ChinaUnix (这次查找其出处时发现2002年就有这篇)。学习过程中,遇到问题就查一下。这次看到,...

    生信宝典
  • 金三银四面试季节——Java 核心面试技术点-《JVM篇》

    从性能的角度看,通常关注三个方面,内存占用(footprint)、延时(latency)和吞吐量(throughput),大多数情况下调优会侧重于其中一个或者两...

    烂猪皮
  • oracle坏块修复实例

    最近几天发现库里有坏块了,环境是11gR2, linux平台的64位的库。以下是我的修复办法,基于dbms_repair做的在线修复,也可以基于备份rman来修...

    jeanron100
  • Java研发方向如何准备BAT技术面试答案(上)

    1. 面向对象和面向过程的区别 面向过程 优点:性能比面向对象高,因为类调用时需要实例化,开销比较大,比较消耗资源;比如单片机、嵌入式开发、Linux/Un...

    zhisheng
  • 不知道吧?Spring Bean初始化/销毁竟然有这么多姿势

    日常开发过程有时需要在应用启动之后加载某些资源,或者在应用关闭之前释放资源。Spring 框架提供相关功能,围绕 Spring Bean 生命周期,可以在 Be...

    黄泽杰

扫码关注云+社区

领取腾讯云代金券