当前位置 博文首页 > why技术:Java并发编程常识

    why技术:Java并发编程常识

    作者:why技术 时间:2021-01-30 15:07

    写中间件经常要做两件事: 1.延迟加载,在内存缓存已加载项。 2.统计调用次数,拦截并发量。 就这么个小功能,团队里的人十有八九写错。分享一下Java并发编程常识。

    这是why的第 85 篇原创文章

    写中间件经常要做两件事:

    • 1.延迟加载,在内存缓存已加载项。
    • 2.统计调用次数,拦截并发量。

    就这么个小功能,团队里的人十有八九写错。


    上面这句话不是我说的,是梁飞在他的博客里面说的。

    梁飞是谁?

    据网上的公开资料,梁飞,花名虚极。

    2009 年加入阿里巴巴,负责中间件的开发,Dubbo 开源分布式服务框架作者,HTTL 开源模板引擎作者。

    2012 年加入天猫,负责手机天猫 APP 的技术团队,见证了天猫双 11 无线化全过程。

    热衷参与开源社区建设,传播服务化、SOA、框架设计、移动应用等架构设计理念。

    下面这段是我在他的个人博客里面找到的:

    https://www.iteye.com/blog/javatar-287026

    上周五去杭州面试,早上飞过去,晚上飞回来,有点匆忙,飞机晚点,到那边的时候都快下午一点了,面试了一个小时左右,主要是笔试没做了,省了不少时间。

    面试完后,跟着几个熟人转了一圈,学习交流气氛都很好。

    周二收到了Offer,看来HR效率很高,赞一个,定的是1月8号入职。

    这两天忙于提交辞职申请,就要离开奋斗了近三年的公司,还是有点不舍,公司给了我很多发展机会,领导们对我也特别好,真的很感谢他们。

    只是现在新的公司发展机遇更好,我不想放弃,希望在新的岗位上能做得更好,呵呵,流水帐记到这里。

    这篇博客,发布于 2008 年 12 月 24 日。

    他说的上周五,也就是 2008 年 12 月 19 日。一天之内,从深圳飞到杭州,面试一小时,又从杭州飞回深圳,4 天之后,收到了阿里的 offer。

    彼时,梁飞也仅从湖南科技职院软件学院的大门走出来不到 3 年的时间。

    文章里面说的“1 月 8 号入职”,也就是 2009 年的 1 月 8 日。

    从此,在阿里开启了长达 12 年的升级打怪之路,从 P5 一路杀到了 P9。

    众所周知,阿里能到 P9 ,已经不是能力的事儿了,这属于祖上积德。

    而梁飞在 2016 年的时候就已经是 P9 了。

    上面说的这么多标签,而他最为人熟知的标签应该是:Dubbo 创始人。

    在梁飞加入阿里的 1015 天之后,也就是 2011 年 10 月 20 日 23 点 06 分,Dubbo 在开源社区发出了第一声啼鸣:

    9 个模块,共计 669 个文件,就是日后这个一路坎坎坷坷、几近夭折、友商续命,最终成为 Apache 顶级开源项目的雏形。

    2011 年 10 月 20 日那天晚上,对于梁飞来说注定是一个回忆起来,难以忘怀的夜晚。

    他一直进行了13 次提交:

    终于在第二天的早上 5 点 25 分给 Dubbo 打上了第一个 tag:2.0.7。

    期间还抽空通知官媒发了个微博:

    而他自己,第二天的中午,也在自己的博客上公布了这件事情:

    为什么 Dubbo 会选在这一天进行开源呢?

    我想应该是为了赶上两天之后的 Qcon 全球软件开发者大会:

    那一天,才是 Dubbo 真正意义上,站在大众视野里,接受赞扬与嘲讽的开始。

    我千辛万苦,找到了近 10 年前,那次大会的分享 PPT,开篇第一页:

    十年过去了,白云苍狗,Dubbo 从阿里走了出来,已经真正的飞入寻常百姓家了。

    十年间,PPT 上的数据,从总量上来看,就像双十一的销售额一样,不知道翻了多少个翻。

    但是转念一想,这是 10 年前的阿里,每天 10 亿次的调用,这是多少技术人一生也接触不到的流量啊。

    同时,我在 PPT 里面也发现很多熟悉的图片,比如这张:

    左边是现在的 Dubbo 官网,右边是 10 年前 Qcon 大会上的 PPT。

    10 年过去了,当这两张图片同框的时候,不知道右边的“老图”,有没有一种老父亲般的欣慰。

    如果说上面这个图你的感觉还不是特别的强烈,那么再看看这个:

    左边是官网,右边是 PPT。

    10 年过去了,整体设计没有发生一丝变化。

    我不知道你看到这里的时候想到的是什么,于我而言,真牛逼啊。

    一个 10 年前的整体设计,竟然在日新月异、风起云涌的互联网行业一丝不变的屹立了下来。

    这是一群工程师智慧的结晶。

    Dubbo 第一次面世的 PPT 有 55 页,里面有很多设计从十年后的今天看去也不过时。

    我就不一一展示了,有兴趣的朋友,在文末可以看到获取方式。

    最后,献上一张最早的 Dubbo 团队的合照:

    Java并发编程常识

    还记得本文开篇的那句话吗?

    https://www.iteye.com/blog/javatar-1963774

    这里的 PPT 链接失效了,我历尽千辛万苦,搜索找到了一份。

    一共 18 页,一一展示一下。

    有的地方是纯知识点,有的地方是代码。

    反正我觉得我看明白了,有必要讲一下的地方。我就在图片下面进行一个简短的描述。

    走起。

    稍微解释一下这一页上面的东西。

    这几个命令,我在之前的文章中也用到过:

    一个困扰我122天的技术问题,我好像知道答案了。

    就是下面这部分:

    所以,我知道这个地方是有个坑的。

    如果你把命令直接粘过去,会抛出这个错误:

    Java HotSpot(TM) 64-Bit Server VM warning: printing of assembly code is enabled; turning on DebugNonSafepoints to gain additional output

    是因为你缺少了一个叫做 hsdis-amd64.dll 的文件(windows平台)。

    你需要把这个文件放在 jre/bin/server 的目录下:

    然后把命令换成这个:

    -XX:+UnlockDiagnosticVMOptions
    -XX:+PrintAssembly
    -XX:CompileCommand=print,*AtomicInteger.incrementAndGet

    再次执行程序,就有汇编输出了:

    再主要说一下 CompileCommand 这个参数。

    这个参数用来定制编译需求,比如可以指定某个方法不做 JIT 编译,也可以只编译指定的方法等等。

    用法是这样的:

    -XX:CompileCommand=command,method[,option]

    其中的 command 有下面这些选项:

    • exclude,跳过编译指定的方法
    • compileonly,只编译指定的方法
    • inline/dontinline,设置是否内联指定方法
    • print,打印生成的汇编代码
    • break,JVM以debug模式运行时,在方法编译开始处设置断点
    • quiet,不打印在此命令之后、通过-XX:CompileCommand指定的编译选项
    • log,记录指定方法的编译日志,若未指定,则记录所有方法的编译日志
    • 其他命令,option,help

    比如 PPT 中的这个用法 -XX:CompileCommand=print,*AtomicInteger.incrementAndGet

    含有就是打印 AtomicInteger.incrementAndGet 方法生成的汇编代码。

    缓冲行对齐,这个应该是一个需要掌握的知识点,属于关于程序优化的奇技淫巧。

    偶现于面试环节。

    对齐的目的是为了解决伪共享(False Sharing)的发生。

    不知道伪共享的朋友,建议去了解一下。

    PPT 中的例子的源码来源是:

    com.google.code.yanf4j.util.LinkedTransferQueue.PaddedAtomicReference

    需要注意的是,在 Java8 里面,提供了更加优雅的解决方案:@Contented 注解。

    这个也是一个非常经典的、关于单例模式的演变过程。

    PPT 上一共四个单例模式的写法,我们一个个的看。

    这就是我们耳熟能详的饿汉式单例。通过提前初始化的方式,解决了并发问题,保证了单例性。

    这里面最关键的就是 final static 关键字。

    作者也用了蓝色做以区分,肯定是有深意的。

    来,一起背一遍类的加载过程:

    加载、验证、准备、解析、初始化。

    比如下面这个例子:

    public static int value =123

    变量 value,只有 static 修饰,那么该变量在准备阶段被赋上初始值,即 0。

    在初始化阶段被赋上 123。

    但是当再多一个 final 修饰的时候:

    下一篇:没有了