《Java 编程思想》读书笔记之并发(一)

一开始咱们作的都是「顺序编程」,可是有时候程序纯顺序执行的性能并不高,而且对于部分问题顺序执行程序并不能很好地解决。程序员

这时候「并发」就是一个很好的解决方案了,「并发」的含义其实很简单,即并行地执行程序中的多个部分。这些部分要么看起来在并发地执行(单处理器环境下经过竞争 cpu 时间片实现同时执行效果),要么在多处理器环境下真正同时执行。编程

并发「具备可论证的肯定性,可是实际上具备不可肯定性」。这是研究并发问题的最强理由:若是视而不见,你就会遭其反噬。-- 《Java 编程思想》多线程

虽然书里是这么讲,可是在实际开发当中,碰到「不可肯定性」的几率比较低(可能我经验不够?),一般碰到的问题都是因为考虑问题不全面,代码 bug 致使,不多碰到所谓的「不可肯定性」。固然,虽然没碰到过,不过听说碰到了多是很是坑爹的,一般连复现问题都比较困难。并发

有时候,虽然你没有主动开启线程使用并发,可是你仍是没法避免并发,Java Web 开发中基本的 Web 类库、Servlet 具备天生的多线程性。负载均衡

并发的多面性

更快的执行

并发一般是用来提升运行在「单处理器」上的程序的性能,可是一般在单处理器上运行的并发程序比该程序的全部部分都顺序执行的开销大,由于增长了所谓的「上下文切换」的代价。那既然开销变大,又怎么会提升性能呢?答案是:「阻塞」,最典型的就是 I/O。从性能的角度看,若是没有任务会阻塞,那么在单处理器机器上使用并发就没有任何意义。性能

在单处理器系统中的性能提升的常见示例是「事件驱动的编程」。若是不使用并发,则产生可响应用户界面的惟一方式就是全部的任务都周期性地检查用户的输入。经过建立单独的执行线程来响应用户的输入,即便这个线程在大多数时间里都是阻塞的,可是程序能够保证具备必定程度的可响应性。—— 《Java 编程思想》操作系统

更多的困难

实现并发最直接的方式是在操做系统级别使用进程。操做系统一般会将进程互相隔离开,进程使用的资源也都是隔离的,进程间相互影响较小,编程也相对简单。与此相反的是,像 Java 所使用的这种并发系统会共享诸如内存和 I/O 这样的资源,所以编写多线程程序最基本的困难在于在协调不一样线程驱动的任务之间对这些资源的使用,以使得这些资源不会同时被多个任务访问。线程

改进代码设计

多线程系统对可用的线程数量的限制一般都会是一个相对较小的数字,有时就是数十或者数百这样的数量级。这个数字在程序控制范围以外可能会发生变化——它可能依赖于平台,或者在 Java 中,依赖于 Java 的版本。设计

在 Java 中,一般要假定你不会得到足够多的线程,从而使得能够为程序中的每一个任务都提供一个线程。解决这个问题的典型方式是使用「协做多线程」。进程

Java 的线程机制是「抢占式」的,这表示调度机制会周期性地中断线程,将上下文切换到另外一个线程,从而为每一个线程都提供时间片。

在协做式系统中,每一个任务都会自动地放弃控制,这要求程序员要有意识地在每一个任务中插入某种类型的让步语句。

协做式系统的优点是双重的:上下文切换的开销一般比抢占式系统要低廉许多,而且对能够同时执行的线程数量在理论上没有任何限制。

并发须要付出代价,包含复杂性代价,可是这些代价与在程序设计、资源负载均衡以及用户方便使用方面的改进相比,就显得微不足道了。线程使你可以建立更加松散耦合的设计,不然,你的代码中各个部分都必须显式地关注那些一般能够由线程来处理的任务。