《Java 并发编程的艺术》迷你书

本文源自InfoQ发表的《Java 并发编程的艺术》电子书  作者:方腾飞  序言:张龙 免费下载此迷你书

250

推荐序

欣闻腾飞兄弟的《聊聊并发》系列文章将要集结成InfoQ迷你书进行发布,我感到非常的振奋。这一系列文章从最开始的发布到现在已经经历了两年多的时间,这两年间,Java世界发生了翻天覆地的变化。Java 7已经发布,而且Java 8也将在下个月姗姗来迟。围绕着JVM已经形成了一个庞大且繁荣的生态圈,Groovy、Scala、Clojure、Ceylon等众多JVM语言在蓬勃发展着,如今的Java已经不是几年前的Java了,众多运行在JVM上的编程语言为我们带来了更多的选择,提供了更好的机会。

纵观这几年的技术发展趋势,唱衰Java的论调一直都萦绕在我们耳边。不可否认,Java的发展确实有些缓慢,而且有些臃肿;但放眼望去,有如此之多的核心与关键系统依旧在使用Java进行开发并运行在JVM之上,这不仅得益于Java语言本身,强大的JVM及繁荣的Java生态圈在这其中更是发挥着重要的作用。在Java的世界中,我们想要完成一件事情有太多可用的选择了。

虽然如此,对于国内的一些开发人员来说,但凡提到Java,想到的都是所谓的SSH(Struts、Spring及Hibernate等相关框架)。不可否认,这些框架对于我们又快又好地完成任务起到了至关重要的推进作用,然而Java并不是SSH,SSH也不是Java的代名词。

由于之前的系列文章都是本人审校的,因此我也非常幸运地成为了这些文章的第一个读者,在阅读之际不禁感叹腾飞的技术造诣及对技术执着的追求。腾飞兄弟的《聊聊并发》系列文章从发布以来一直高居InfoQ中文站浏览量的前列,每篇文章之后都有大量的读者评论,或是提问,或是补充相关知识,腾飞兄弟也都非常耐心地对读者的问题进行解答。并发是一个学科,Java中也有自己的一套处理并发的框架与体系;不过遗憾的是,很多读者对这一领域知之甚少,这也直接造成了很多人并不了解有关并发的理论与实践知识。幸运的是,腾飞的《聊聊并发》系列文章非常完美地填补了这一空白,文章从synchronized关键字、volatile实现原理到ConcurrentHashMap、ConcurrentLinkedQueue源码分析,再到阻塞队列和Fork/Join框架,为读者献上了一道丰盛的Java并发大餐。

相信腾飞以在淘宝的实际工作经验凝结而成的这部InfoQ迷你书会为广大读者打开通往Java并发之路的大门。这里我要小声做一个提示,也许文章中很多内容看一次未必就能完全消化吸收,这时请不要放弃,多看几次,多动手做实验,相信你会很快掌握Java并发的精髓的。

另外,值得一提的是,腾飞兄弟现在在维护着一个关于Java并发资源的站点——并发编程网(http://ifeve.com/),上面有大量高质量的原创与翻译文章,都是关于并发领域相关内容的,感兴趣的读者不妨移步一观。

最后,祝大家阅读愉快,能够轻松驾驭Java并发。

是为序。

InfoQ中文站Java主编:张龙

本书节选了成书的两个章节,完整版将由机械工业出版社华章公司于2015年发售,完整阅读需耐心等待。

原创文章,转载请注明: 转载自并发编程网 – ifeve.com本文链接地址: 《Java 并发编程的艺术》迷你书

  • Trackback 关闭
  • 评论 (44)
    • Snway
    • 2014/02/25 9:29下午

    恭喜恭喜,加油方兄!!!

    • felix
    • 2014/02/28 8:58上午

    我运行这段代码:
    final HashMap map = new HashMap(2);

    Thread t = new Thread(new Runnable() {

    public void run() {
    for(int i = 0;i <1000;i++){
    new Thread(new Runnable() {

    public void run() {
    map.put(UUID.randomUUID().toString(), "");
    }
    }, "ftf" + i).start();
    }
    }
    }, "ftf");

    t.start();
    t.join();
    并未发现CPU使用率近100%,维持在50%左右,而是直接内存溢出,这是为何呢?

    • 内存溢出应该和这短代码没关系。

      • 博主,我用JDK 8(b129, Mac 10.9)运行了上面的代码,第一次运行报错:ClassCastException(关于TreeNode和Node转换的,感觉像是JDK自身的问题),但是重新运行就正常了。
        而且没有死循环出现,可能是JDK8对HashMap改造以后不会出现这个问题了,期待博主抽空研究下,thanks,特别是JDK8的ConcurrentHashMap,看的有点晕。

        • yangboa
        • 2017/02/07 4:34下午

        您好,方老师,请问下您有并发编程相关的视频教程么?在哪里可以购买到?

    • 李 任
    • 2014/02/28 12:08下午

    期待完整版上市

    • 云淡风轻
    • 2014/03/07 4:37下午

    期待阅读

  1. 刚看了下迷你书的ConcurrentHashMap的部分,关于再哈希的原因描述,觉得有点不太恰当,单从理论上来讲,对一个哈希值再次哈希,不可能改良这个哈希值,只可能增加碰撞机率,ConcurrentHashMap之所以再哈希,是因为它使用哈希值的时候,只使用了其中的一部分bit,所以才需要再次哈希,将所有bit都加入计算,来减少部分bit相同时引发的碰撞。后面你也提到了它是如何使用那个哈希值的,但如果把这与前面结合起来讲,我觉得可能更方便读者理解。

    • hello
    • 2014/03/26 1:42下午

    深入jvm,和之前的java并发编程等书籍相比,本书的卖点是什么?

    • 匿名
    • 2014/06/11 3:55下午

    这本书,一定会买。

    • 匿名
    • 2014/08/14 6:42下午

    期待啊,不知道什么时候会出完整版?

    • wangwangheng
    • 2015/02/28 6:35下午

    亲,这本书什么时候出啊,等了好久了。 。。!有具体日期么 !?

    • 预计5月份,基本已经写完了,正在编辑

    • 已经发布了

        • 孔令秋
        • 2015/09/17 7:50下午

        你好,我现在正在看java并发编程的艺术,在concurrentLinkedQueue一节中在入队列时获取p节点的下一个节点的succ方法中
        final Node succ(Node p){
        Node next = p.getNext();
        return (p == next) ? head :next;
        }
        这里你说获取tail节点的next节点需要注意的是p节点等于p的next节点的情况,只有一种可能就是p节点和p的next节点都等于空
        这里在创建concurrentLinkedQueue对象时
        public ConcurrentLinkedQueue() {
        head = tail = new Node(null);
        }
        已经初始化了tail节点,p怎么可能还为空呢,还有p如果为空,p.getNext()这里会报空指针啊???
        想了一天也没想明白为什么p.getNext能和p相等,我觉得应该是p.getNext和p.getItem相等啊
        求解答!!!万分感谢

  2. 很是期待完整,可惜要5月份啊

    • epidemic
    • 2015/03/04 9:53下午

    我还是买一本吧。

    • Mrsunsunshine
    • 2015/04/24 9:29下午

    现在可以买到全书了吗?

    • sunsai
    • 2015/05/05 10:32上午

    什么时候可以买到啊

    • larry.su
    • 2015/06/04 10:54上午

    6月份了,全书快出来了吧

    • Mrsunsunshine
    • 2015/07/02 9:03上午

    7月份了,方腾兄书还没出吗?

    • 正在出版中,预计七月份预售,八月份能到读者手中。

    • zhaoloon
    • 2015/08/24 6:42下午

    以入手,书很不错。

    • 下雨不打伞
    • 2015/09/06 9:43上午

    你好,99页的WaitNotify.java 有些理解上的问题,Wait类的run方法中使用了代码块同步,用的是lock的监视器锁。Notify类的run方法也使用了lock监视器锁的代码块。WaitThread线程先执行,那么应该是先拿到lock的监视器锁,NotifyThread应该会因为拿不到监视器锁而阻塞啊,为什么程序会能正常执行完?

    • 辰南
    • 2016/01/22 5:30下午

    你好,Java8 ConcurrentHashMap做了蛮多的改动,有没有考虑专门写一篇文章对书中的CHM那一章进行一些改进。

    • q742964708
    • 2019/04/19 10:30上午

    您好,您在第一章中说到了线程切换时切换了上下文,请问这个“上下文”包含了哪些信息以及切换时都做了哪些操作?

    • mworld
    • 2020/04/09 10:04下午

    请问下《Java并发编程的艺术中》
    第二章,第2.1节 第10页
    Lock前缀指令导致在执行指令期间,【声言】处理器的LOCK#信号。

    这里【声言】是什么意思,本意是想说声明么?

    • JonathanJoestar
    • 2021/02/27 3:35下午

    请问《Java 并发编程艺术中》

    第二章,第2.2节第9页:”……Lock前缀的指令,将这个变量所在缓存行的数据写回到系统内存”

    那么 lock addl $0x0,(%esp); 就是 StoreLoad barriers 本身,要将当前处理器写缓冲区中的数据全部刷新到内存中。

    到底哪个是对的呢,我应该修改一下书中第二章的内容吗

      • JonathanJoestar
      • 2021/02/27 3:57下午

      如果程序正确同步,程序的执行结果与在顺序一致性内存模型中的执行结果相同。

      而对一个 volatile 域的写,happens-before 于任意后续对这个 volatile 域的读

      Java语言规范:对volatile变量v的写入与任何线程对变量v的所有后续读取同步

      于是 volatile 写不仅仅是一个变量所在缓存块被写回到系统内容,而是所有共享变量所在缓存块被写回到系统内容???

        • JonathanJoestar
        • 2021/02/27 5:23下午

        还是说写缓冲区中的数据全部被刷新到内存中,并且确保该volatile变量所在缓存行被写回到系统内容?

        • JonathanJoestar
        • 2021/02/27 5:27下午

        第二章第九页的内容其实还缺一部分,是这样的吧

    • JonathanJoestar
    • 2021/03/21 5:33下午

    Doug Lea 不是说 StoreLoad 屏障有其他延迟的实现吗。 MESI 协议,刷新 store buffer 是刷新到高速缓存中,既然是高速缓存应该无法通过嗅探机制来无效缓存,那么 volatile 读仍然要使用 MESI 的 read-barrier 来保证其他 CPU 的所有写入对于当前 CPU 是可见的不是吗

      • JonathanJoestar
      • 2021/03/21 6:16下午

      不是,Doug Lead 写的 StoreLoad 屏障也没说刷新到内存啊。。。

        • JonathanJoestar
        • 2021/03/21 6:17下午

        emm…但是好像这样理解也可以,但是实现和 MESI 好矛盾

        • JonathanJoestar
        • 2021/03/23 6:06下午

        明白了,作者这里还有内存屏障的文章啊

      • JonathanJoestar
      • 2021/03/25 4:33下午

      我弄混了,x86 StoreLoad 屏障的实现是回写到内存,并且x86 并没有 MESI 的 invalidate queue 概念。评论撤回不了了

      • JonathanJoestar
      • 2021/03/28 3:18下午

      经过我的仔细思考,书中对 StoreStore 和 StoreLoad 屏障的描述:”确保 Store1 数据加对其他处理器变得可见(指刷新到内存)”,还有 “因为当前处理器通常要把写缓冲区中的数据全部刷新到内存中(buffer fully flush)”

      应该改成 “确保 Store1 数据加对其他处理器变得可见(例如刷新到内存)”,”因为当前处理器通常要对写缓冲区进行一个彻底的刷新(buffer fully flush)”

    • newbie
    • 2021/08/07 3:59下午

    java并发编程的艺术第10页讲到,Lock前缀指令会引起处理器缓存回写到内存, 而处理器缓存回写到内存,会通过总线嗅探导致其他处理器的缓存无效。第41页说到volatile写会把共享变量的值刷新回主存,volatile读取时把本地内存置为无效。 这里如何理解,volatile变量缓存失效实质上是在写的时候发生的还是读的时候发生的? 如果是读的时候发生的, 那写一次变量, 后面读10次就会失效十次, 显然不太合理吧?

    • drug
    • 2022/09/08 11:33上午

    书有编写错误

return top