第1章 介绍
编写正确的程序难,编写正确的并发程序更难。与串行程序相比,在并发程序中有更多容易出错的东西。那么,为什么我们要关心并发呢?线程是Java语言的一个不可忽视的特性,使用线程可以将复杂的异步代码调整为简单直线式代码,从而简化复杂系统的开发。此外,线程是开发利用多处理器系统计算能力最容易的方式。随着处理器数量的增加,有效地利用并发将变得越来越重要。
1.1 并发的(非常)简短历史
在过去,计算机没有操作系统;计算机从开始到结束仅执行一个单一程序,此程序直接访问机器的所有资源。如此情况,不但编写运行于裸机上的程序是困难的,而且某一时刻仅运行一个单一程序也是对昂贵而稀缺的计算机资源的低效使用。
操作系统发展到允许多个程序同时运行,每个进程中运行一个独立的程序:程序是隔离的,独立执行的,操作系统为程序分配像内存、文件句柄和安全证书这样的资源。如果进程需要与另一个进程通信,可以通过各种粗粒度的通信机制:套接字(socket)、信号处理器(signal handlers)、共享内存(shared memory)、信号量(semaphores)和文件(files)。
多种促进因素推动操作系统允许多个程序同时执行:
资源利用。程序有时候必须等待像输入或输出这样的外部操作,而等待期间又不能做一些有用的工作。利用这段等待时间让另外一个程序运行显得更有效。
公平。多个用户和应用程序可能对机器资源有平等的要求。让多个程序通过细粒度的时间片共享计算机比让一个程序运行完再启动另一个程序更可取。
便利。编写多个程序,每个程序执行一个单一任务,在必要的时候让它们互相协调,这要比编写一个执行所有任务的单一程序更容易,更令人满意。
在早期的分时系统中,每个进程就是一个虚拟的冯诺依曼计算机;进程有一个存储指令和数据的内存空间,根据机器语言的语义顺序执行指令,通过操作系统的一组I/O原语与外界交互。对于每条执行的执令都有一个对“下一条指令”清晰的定义,并根据指令集的规则控制程序流程。今天几乎所有广泛使用的编程语言都遵循串行编程模型,在其语义规范中明确定义了在一个特定动作执行之后“下一个动作是什么”。
串行编程模型既直观又自然,因为它模仿了人类的工作方式:一次只做一件事,大多数时候是按顺序去做的。起床,穿上睡衣,下楼,开始准备茶点。就像在编程语言中一样,这些现实世界中的每个动作都是一个细粒度动作序列的抽象----打开橱柜,选一款茶叶,取适量放入茶壶,看水壶中是否有足够的水,如果没有则在水壶中加一些水,把水壶放到炉子上,打开炉子,等水烧开,等等。最后一步----等水烧开----也意味着某种程度的异步。在水加热的过程中,你可以干等,也可以在此时做一些其他任务,例如开始烤面包(另一个异步任务)或者取份报纸回来,同时要知道得留意水壶。水壶和烤箱的生产厂商了解他们的产品经常在异步方式下使用,所以当水壶或烤箱完成工作时会发出声响信号。找出串行和异步之间适当的平衡通常是高效人士的特征----程序也是如此。
相同的关注点(资源利用,公平和便利)不仅激发了进程的发展,也促进了线程的发展。线程允许程序控制流的多个分支共存于一个进程中。线程共享进程范围内的资源,例如内存和文件句柄,但每个线程有自己的程序计数器,堆栈和本地变量。线程也提供了在多处理器系统上对硬件并行利用的自然分解(译注:以线程为单位有效分配硬件资源,发挥出硬件并行的优势);在同一个程序中的多个线程可以在多个CPU上同时调度。
线程有时称为轻量级进程,大多数现代操作系统都将线程,而不是进程,作为调度的基本单位。
posted on 2011-08-24 18:01
jeffma 阅读(2183)
评论(2) 编辑 收藏