Java并发编程学习路线

一年前由于工作需要从微软技术栈入坑Java,并陆陆续续做了一个Java后台项目,目前在搞Scala+Java混合的后台开发,一直觉得并发编程是所有后台工程师的基本功,所以也学习了小一年Java的并发工具,对整体的并发理解乃至分布式都有一定的提高,所以想和大家分享一下。

我的学习路线

首先说说学习路线,我一开始是直接上手JCIP(Java Concurrency in Practice),发现不是很好懂,把握不了那本书的主线,所以思索着从国内的作者开始先,所以便读了下方腾飞的《Java并发编程的艺术》的,虽然豆瓣上的评价一般,但是对于构建Java并发的整体映像还是有所提高的,至少我知道了有哪些东西要深入学习。接着我想加强下并发的理论,继续读了The Art of Multiprocessor Programming,这本书比较艰涩,不是很好懂,但是过一遍还是好处多多,建议初学者了解下概念的过过,后期可以再来翻看。有了以上两步的支持,接下来就又开始啃JCIP了,发现比以前有了不同的感觉,我能比较轻松的跟上书的脉络,知道书的整体框架,读起来不那么费劲了,这本书号称Java并发编程的圣经,确实可以看出作者有很丰富的并发实践经验。再后来我过了一遍Oracle官网上的Java Tutorial关于并发的那一章,发现讲的也不错,对于了解基础库有哪些组件帮助挺大。

到了这一步,接下来怎么继续提高呢?我发现了一本很有趣的书,《七周七并发模型》,之前的视野一直是在Java并发编程的工具包中深入了解,感觉,应该跳出来,从模型的角度看看各个语言的并发实现的原理,我目前正处于这一步,发现很有意思,第一章讲Java的线程和锁这个模型就感觉很精髓,只用了小三章把Java整体的脉络过了一遍,强烈推荐用来复习。

下一步我的计划是jdk的concurrent包以及Java specification的并发部分,并发理解,除了基础概念,就是要深刻领会各个应用场景下,有无并发问题以及如何写出线程安全的代码,个人觉得学习下无锁的实现对理解有一定的帮助,但不用太费心思,到了Java Memory Model这一层基本就够用了。

根据上面的阐述,我的路线图可以总结如下:

学习心得 -- Java并发包的基础概念

了解Java并发包有哪些工具以及相关基础概念,有Java tutorial的concurrent章节和JCIP一书就足够了。

JCIP一书的整体脉络如下:

  1. 介绍多线程的利弊;
  2. 解释线程安全是什么以及如何获得线程安全;
  3. 从高频的使用场景出发,介绍对象传递,类的设计等如何获得线程安全;
  4. 从Java并发包出发,介绍高层的并发组件有啥以及相关原理;
  5. 介绍并发的一些弊端以及如何避免;
  6. 从Java并发包出发,介绍底层的并发组件以及原理;

总体看,该书有两条主线,1 从高到低介绍Java并发包的一些重要组件和原理; 2 从并发场景出发,介绍如何利用这些组件来获得线程安全。其中第二部分是这本书最大的特色,也是书名中有Practice的原因。

书中提到了几个比较有意思的地方,

首先,到底什么是线程安全?

A class is thread-safe if it behaves correctly when accessed from multiple threads, regardless of the scheduling or interleaving of the execution of those threads by the runtime environment, and with no additional synchronization or other coordination on the part of the calling code.
这个定义中,作者强调了正确地被多线程访问, 同时要求没有外加其他同步的手段。

那么,如何获得线程安全?
Writing thread-safe code is, at its core, about managing access to state, and in particular to shared, mutable state.
书中将获得线程安全总结为维护代码的状态,如果一个类是无状态的(immutable),则自带线程安全的属性(函数式编程便是通过这种方式达到自带的线程安全)。这些状态大致可以理解为类中的非常量变量。 
通过这个可以了解到线程安全的本质,其实是共享变量,也就是状态,有状态的多线程访问就需要同步机制来保证线程安全。

如何理解Java提供的用于处理并发的组件?
JDK提供的并发组件,大致可以分为两类, 一类是预防为主,防止错误发生(race condition, visibility),大部分组件都是这类,还有一类是发生了错误但是能够知道并及时重试(Atomic类提供的CAS),形象的例子有如 十字路口的信号灯,在流量小的时候,采用过多的预防措施反而会适得其反,例如白白的在大部分时间都没有车的道路上等红灯,这个时候适合采用犯错(例如去掉红绿灯,让车自由行驶,遇到其他车的时候互相让位即可)后解决的方法,能够获得最大的效率,在流量大的时候,红绿灯的作用就能够凸显出来,其实规则的制定一定是在规模较大的时候才有意义,这也是预防的初衷。
类比到并发领域就是,在线程数量大,采用预防的措施比较好,这样大部分线程就不会因为概率小的CAS重试浪费大量的cpu周期,在线程数量小的时候,CAS的意义就比较大,因为预防措施带来的线程切换等的开销可能大于CAS的等待,而且较少的线程也会让CAS重试的等待时间变少。

以下是我根据这两个资料概括出来的基础概念,

理解这些基础概念的核心,我觉得其实就是解决两点问题:

  • Thread Interleaving,即多个线程读写共享变量造成的不一致问题;
  • Visibility,为了提高性能,处理器的每个执行单元其实都有缓存,这个虽然提高了某些数据的访问性能但是却给并发编程带来了数据读取的不一致性问题;

当然要更深入理解并发,还需要知道如何提升并发的性能,例如锁的粒度如何把握?(经典的例子可以JDK的ConcurrentHashMap),底层一点的知识也得了解,例如CAS和Java Memory Model。

从高维视角了解并发

有了Java并发的基础知识,接下来很适合阅读七周七并发,我目前就在读七周七并发,发现站在多种语言从范式的角度了解并发很有意思,原来Java提供的线程和锁的机制其实相当于比较原始的工具了,其离底层最近。最近接触了Scala,其使用了AKKA,则是一种高层的并发抽象。

七周七并发试图从历史的角度阐述作为锁和线程的代表之Java的并发包的进化历程,首先最早加入JDK的,其实是synchronized及其statement,但是发现缺少相关timeout和不能中断等等功能,加入了可重入锁,读写锁等等,再后来又加入了各种线程安全的数据结构和高级同步机制。

接下来,七周七并发从函数式编程等等各种范式的角度阐述,除了线程和锁,还有很多其他高层抽象可以更加方便的编写并发代码。

这本书对于充分理解并发,拓宽视野很有帮助,推荐大家阅读。

从实现角度透彻理解并发

再深入下去的话,没有比经典的JDK更合适的了,当然Google的Guava包也值得学习,从这些经典代码了解各种组件的实现可以加深理解并更好的使用它们,但是作为应用端的程序员,倒是并不需要写出这种较为底层的代码(无锁化)。

回顾这小一年的学习曲线,收获良多,不过最后最值得强调的一点其实是,在做技术选择的时候,并发只是工具箱中的一种手段,学习它只是为了能够灵活运用,设计的首要选择依然是在当时情境下的最简化,能不用并发就不要用。

时间: 2024-08-10 13:44:56

Java并发编程学习路线的相关文章

Java并发编程学习笔记(一)线程安全性 1

什么是线程安全性: 要编写线程安全的代码,其核心在于要对状态访问操作进行管理,特别是对共享的和可变的状态的访问."共享"意味着变量可以由多个线程同时访问,而"可变"则意味着变量的值在其生命周期内可以发生变化. 一个对象是否需要线程安全的,取决于他是否被多个线程访问.这指的是在程序中访问对象的方式,而不是对象要实现的功能.要使得对象时线程安全的,需要采用同步机制来协同对对象可变状态的访问.如果无法实现协同,那么可能导致数据破坏以及其他不该出现的结果. 如果当多个线程访

Java并发编程学习笔记

Java编程思想,并发编程学习笔记. 一.基本的线程机制 1.定义任务:Runnable接口 线程可以驱动任务,因此需要一种描述任务的方式,这可以由Runnable接口来提供.要想定义任务,只需实现Runnable接口并编写run方法,使得该任务可以执行你的命令.   class MyTask implements Runnable {    private String mName;     public MyTask(String name) {    mName = name;   }  

学习笔记:java并发编程学习之初识Concurrent

一.初识Concurrent 第一次看见concurrent的使用是在同事写的一个抽取系统代码里,当时这部分代码没有完成,有许多的问题,另一个同事接手了这部分代码的功能开发,由于他没有多线程开发的经验,所以我就一起帮着分析.最开始看到这个时很烦燥啊,因为自己接触java时间很短,连synchronized都不知道怎么用呢,突然发现有这么个复杂的东西.当时就只好开始学习吧,毕竟是使用嘛,第一目的就是了解清楚这玩意的各个类与方法都干嘛用的,然后看了看同事的代码大概也就清楚了.感觉这和大部分人一样,能

Java并发指南开篇:Java并发编程学习大纲

Java并发编程一直是Java程序员必须懂但又是很难懂的技术内容. 这里不仅仅是指使用简单的多线程编程,或者使用juc的某个类.当然这些都是并发编程的基本知识,除了使用这些工具以外,Java并发编程中涉及到的技术原理十分丰富.为了更好地把并发知识形成一个体系,也鉴于本人没有能力写出这类文章,于是参考几位并发编程专家的博客和书籍,做一个简单的整理. 一:并发基础和多线程 首先需要学习的就是并发的基础知识,什么是并发,为什么要并发,多线程的概念,线程安全的概念等. 然后学会使用Java中的Threa

[Todo] Java并发编程学习

有两个系列的博文,交替着可以看看: 1. Java并发编程与技术内幕 http://blog.csdn.net/Evankaka/article/details/51866242 2. [Java并发编程]并发编程大合集 http://blog.csdn.net/ns_code/article/details/17539599

java并发编程学习:用 Semaphore (信号量)控制并发资源

并发编程这方面以前关注得比较少,恶补一下,推荐一个好的网站:并发编程网 - ifeve.com,上面全是各种大牛原创或编译的并发编程文章. 今天先来学习Semaphore(信号量),字面上看,根本不知道这东西是干啥的,借用 并发工具类(三)控制并发线程数的Semaphore一文中的交通红绿信号灯的例子来理解一下: 一条4车道的主干道,假设100米长,每辆车假设占用的长度为10米(考虑到前后车距),也就是说这条道上满负载运行的话,最多只能容纳4*(100/10)=40辆车,如果有120辆车要通过的

java并发编程-学习

disruptor:https://www.cnblogs.com/sigm/p/6251910.html 自旋锁等:http://www.cnblogs.com/lzh-blogs/p/7477157.html 1.竞态条件:多个线程共享相同的内存地址空间,并且并发执行下发生访问或修改其他线程正在使用的变量,而导致结果不一致. 2.活跃性:某件正确的事情最终发生,但不够好,因此需要解决性能问题 3.在多线程中,当线程调度器临时挂起活跃线程并转而运行另外一个线程时,就会产生频繁的上下文切换(Co

Java并发编程学习笔记(一)——线程安全性

1.当多个线程访问某个状态变量并且其中有一个献策灰姑娘执行写入操作时,必须采用同步机制来协同这些线程对变量的访问.Java中的主要同步机制是关键字synchronized,他提供了一种独占的加锁方式. 2.在任何情况下,只有当类中仅包含自己的状态时,线程安全类才是有意义的. 3.当多个线程访问某个类时,不管运行时环境采用何种调度方式或者这些献策灰姑娘讲如何交替执行,并且在主调代码中不需要任何额外的同步或协同,这个类都能表现出正确的行为,那么就称这个类是线程安全的. 4.无状态对象一定是线程安全的

Java并发编程学习:线程安全与锁优化

本文参考<深入理解java虚拟机第二版> 一.什么是线程安全? 这里我借<Java Concurrency In Practice>里面的话:当多个线程访问一个对象,如果不考虑这些线程在运行时环境下的调度和交替执行,也不需要额外的同步,或者调用方进行任何其他的协调操作,调用这个对象的行为都可以获得正确的结果,那么这个对象是线程安全的. 我的理解:多线程访问一个对象,任何情况下,都能保持正确行为,就是对象就是安全的. 我们可以将Java语言中各种操作共享的数据分为以下5类:不可变.