第15章 多线程编程 本章将要讲述Java中线程(Thread)相关的内容。它是一个全新的事物。为了理解本 章的内容,需要用到前面学到的以下知识点。 口方法的调用过程: 口程序执行流程; 口继承和覆盖: 口接口和内部类: 口类文件即是Java平台的可执行文件。 线程原本是操作系统中的一个概念。在绝大多数平台上,Java平台中的线程其实就是 利用了操作系统本身的线程。对于学习Jva线程而言,最重要的内容是理解线程。在理解 了线程之后,再去学习Java中常用的线程编程其实不难。除了介绍线程的概念,本章还会 讲解Java线程的使用、多线程编程和线程同步的基本知识。这些都是最常用的线程编程 技术。 本章15.1节用来讲述线程的概念,是本章中最重要的一节。对于线程这种抽象的概念, 一次看不懂也是正常的。15.1节是全章的基础,理解了15.1节的内容,本章剩余的内容就 不难理解了。所以请读者在继续后面的内容之前,务必将15.1节的内容看懂。好,下面首 先理解线程的概念。 15.1线程—执行代码的机器 线程是编程中极其重要的一部分内容,但是对于初学线程的读者来说,它的概念显得 过于抽象而不好理解。和程序的代码不同,线程是隐藏在程序背后的,对于编程者来说它 是看不见摸不着的。为了形象地描绘线程的作用,本节将使用一个“CD机模型”和“演 奏会模型”来与线程进行类比。为了明白线程,首先需要了解Java程序是如何运行的。 15.1.1线程一执行代码的基本单位 什么是线程呢?它不是Java语言语法的一部分。在Java中,线程可以说是一个“机 器”,它的作用就是执行Java代码。换句话说,Java中的代码,都是通过线程为基本单位 来执行的。图l5-1描绘了前面学习的从Java源代码到生成Java类文件的过程。 相信这个过程大家并不陌生,本章后面的内容对上面这个过程将不再叙述。生成了Java 类文件之后,就是运行Java程序了。上段中说过,线程是Java中程序执行的基本单位, 执行一个Java程序(有main0方法的Java类)的过程如图l5-2所示
第 15 章 多线程编程 本章将要讲述 Java 中线程(Thread)相关的内容。它是一个全新的事物。为了理解本 章的内容,需要用到前面学到的以下知识点。 方法的调用过程; 程序执行流程; 继承和覆盖; 接口和内部类; 类文件即是 Java 平台的可执行文件。 线程原本是操作系统中的一个概念。在绝大多数平台上,Java 平台中的线程其实就是 利用了操作系统本身的线程。对于学习 Java 线程而言,最重要的内容是理解线程。在理解 了线程之后,再去学习 Java 中常用的线程编程其实不难。除了介绍线程的概念,本章还会 讲解 Java 线程的使用、多线程编程和线程同步的基本知识。这些都是最常用的线程编程 技术。 本章 15.1 节用来讲述线程的概念,是本章中最重要的一节。对于线程这种抽象的概念, 一次看不懂也是正常的。15.1 节是全章的基础,理解了 15.1 节的内容,本章剩余的内容就 不难理解了。所以请读者在继续后面的内容之前,务必将 15.1 节的内容看懂。好,下面首 先理解线程的概念。 15.1 线程——执行代码的机器 线程是编程中极其重要的一部分内容,但是对于初学线程的读者来说,它的概念显得 过于抽象而不好理解。和程序的代码不同,线程是隐藏在程序背后的,对于编程者来说它 是看不见摸不着的。为了形象地描绘线程的作用,本节将使用一个“CD 机模型”和“演 奏会模型”来与线程进行类比。为了明白线程,首先需要了解 Java 程序是如何运行的。 15.1.1 线程——执行代码的基本单位 什么是线程呢?它不是 Java 语言语法的一部分。在 Java 中,线程可以说是一个“机 器”,它的作用就是执行 Java 代码。换句话说,Java 中的代码,都是通过线程为基本单位 来执行的。图 15-1 描绘了前面学习的从 Java 源代码到生成 Java 类文件的过程。 相信这个过程大家并不陌生,本章后面的内容对上面这个过程将不再叙述。生成了 Java 类文件之后,就是运行 Java 程序了。上段中说过,线程是 Java 中程序执行的基本单位, 执行一个 Java 程序(有 main()方法的 Java 类)的过程如图 15-2 所示
第15章多线程编程 编写Java源文件 编译Java源文件 -没有语法错误· 生成class文件 有语法错误 图15-1生成Java类文件的过程 Java平台 读取并加载class文件 创建一个线程 启ava平台 Java平台退出 让线程从main(O方法 开始执行程序 main(方法结束,线 程也随之结束 图15-2Java程序执行过程 在图l5-2中,启动Java平台就是我们在命令行执行java命令,Java平台退出就是java 命令执行结束。中间的图表示了Java平台执行的过程。因为是在控制台上直接使用java 命令执行一个类文件的,所以很容易觉得java命令是执行Java代码的基本单位。实际上, java命令是通过创建一个Java线程来执行Java代码的。 □说明:Java线程当然也是Java平台的一部分。在本章中为了突出Java线程,从概念上 将它从Java平台中剥离了出来单独讲解。 1.Java线程和CD机 从线程的角度来看,Java平台更像是一个线程管理器。下面我们通过一个例子,来说 明类文件、Java线程和Java平台的关系。大家都用过CD机,CD机中读取CD碟片内容 的部件就是CD机上的激光头。CD和Java之间各个元素可以做如下类比,如图15-3所示。 class文件 CD碟片 Java线程 CD机中的激光头 Java平台 CD机 图15-3Java和CD的对比 ·439·
第 15 章 多线程编程 ·439· 图 15-1 生成 Java 类文件的过程 图 15-2 Java 程序执行过程 在图 15-2 中,启动 Java 平台就是我们在命令行执行 java 命令,Java 平台退出就是 java 命令执行结束。中间的图表示了 Java 平台执行的过程。因为是在控制台上直接使用 java 命令执行一个类文件的,所以很容易觉得 java 命令是执行 Java 代码的基本单位。实际上, java 命令是通过创建一个 Java 线程来执行 Java 代码的。 说明:Java 线程当然也是 Java 平台的一部分。在本章中为了突出 Java 线程,从概念上 将它从 Java 平台中剥离了出来单独讲解。 1.Java线程和CD机 从线程的角度来看,Java 平台更像是一个线程管理器。下面我们通过一个例子,来说 明类文件、Java 线程和 Java 平台的关系。大家都用过 CD 机,CD 机中读取 CD 碟片内容 的部件就是 CD 机上的激光头。CD 和 Java 之间各个元素可以做如下类比,如图 15-3 所示。 图 15-3 Java 和 CD 的对比
第2篇Java语言高级语法 class文件就如同CD碟片:class文件中包含Java程序的可执行代码:CD中包含着音 乐文件。它们都是数据的载体。 Java线程就如同CD中的激光头:Java线程负责执行class文件中的代码:激光头负责 读取并处理CD上的音乐文件。它们都是负责处理数据的。 Java平台就如同CD机:Java平台包含Java线程,然后,Java线程还负责管理Java 线程,包括创建Java线程,为Java线程提供各种资源(在这里不去深究是什么资源,可 以将之理解为Java线程执行代码的各种基础条件):CD机包括激光头,同时它也管理着 激光头,为激光头供电,同时还提供外壳、马达、播放控制、音频解码和音频输出等各种 功能,没有这些功能,激光头本身无法处理数据。Java平台和CD机可以说是独立的系统, 可以完成一个功能:线程和激光头是它们中的核心部件,但是并不是可独立完成整个工作 的部件。 2.从CD机的工作机制看Java线程 通过上面这个例子,相信线程这个概念己经不完全陌生了。对于激光头,它会从CD 的某个位置开始,按照顺序读取CD上的数据。那么线程的工作模式是怎样的呢?其实和 激光头很类似一只要给线程一个“开头”,线程就会一直沿着这个“开头”执行下去。 对于前面的所有例程来说,这个“开头”在图15-2中已经说明了,它就是我们再熟悉不过 的main()方法。也就是说,线程会从main()方法开始执行程序。 CD机的作用就是播放音乐,当CD在播放完CD后,激光头就会关闭,CD机也会自 动关机。同样的道理,Java平台的作用就是执行Java程序代码。线程在执行完main()方法 后,也就结束了。而当Java平台发现自己里面的线程都退出以后,也就会退出。这时Java 程序就运行完毕了。 那么,线程是如何执行代码的呢?这个超出了本书的范围。就好像使用CD机一样, 使用者只要知道CD机中激光头是用来读取和处理CD碟片上的内容就可以了,没必要去 追究它是如何读取CD碟片上的内容的。对于线程也是一样的道理。前面说过,线程是操 作系统中的一个概念,所以“线程是如何执行程序的”这个问题属于操作系统课程中的内 容。对于学习Java而言,在这里先知道如下几点就可以了。 口线程是执行Java程序代码的基本单位。 口Java线程也是Java平台的一部分。 口Java线程是运行在Java平台内部的,Java平台负责管理Java线程。 口Java线程执行程序代码时,Java平台为其提供各种所需的条件。 口当线程执行完给它的方法后,就会退出。Java平台中如果没有正在运行的线程, 就代表程序执行完毕,Java平台也就自动退出了。 本节的内容就先到这里。本节中使用的“CD机模型”比较容易理解,但是它和线程 还不是十分相似。在15.1.2节中将通过“演奏会模型”来加深对线程的理解。 15.1.2演奏会模型 线程是隐藏在Java平台之中的,它的工作方式并没有展露在Java语法中。我们只能 够通过类比的方式来理解Java线程以及程序代码、Java线程和Java平台三者之间的关系。 ·440·
第 2 篇 Java 语言高级语法 ·440· class 文件就如同 CD 碟片:class 文件中包含 Java 程序的可执行代码;CD 中包含着音 乐文件。它们都是数据的载体。 Java 线程就如同 CD 中的激光头:Java 线程负责执行 class 文件中的代码;激光头负责 读取并处理 CD 上的音乐文件。它们都是负责处理数据的。 Java 平台就如同 CD 机:Java 平台包含 Java 线程,然后,Java 线程还负责管理 Java 线程,包括创建 Java 线程,为 Java 线程提供各种资源(在这里不去深究是什么资源,可 以将之理解为 Java 线程执行代码的各种基础条件);CD 机包括激光头,同时它也管理着 激光头,为激光头供电,同时还提供外壳、马达、播放控制、音频解码和音频输出等各种 功能,没有这些功能,激光头本身无法处理数据。Java 平台和 CD 机可以说是独立的系统, 可以完成一个功能;线程和激光头是它们中的核心部件,但是并不是可独立完成整个工作 的部件。 2.从CD机的工作机制看Java线程 通过上面这个例子,相信线程这个概念已经不完全陌生了。对于激光头,它会从 CD 的某个位置开始,按照顺序读取 CD 上的数据。那么线程的工作模式是怎样的呢?其实和 激光头很类似——只要给线程一个“开头”,线程就会一直沿着这个“开头”执行下去。 对于前面的所有例程来说,这个“开头”在图 15-2 中已经说明了,它就是我们再熟悉不过 的 main()方法。也就是说,线程会从 main()方法开始执行程序。 CD 机的作用就是播放音乐,当 CD 在播放完 CD 后,激光头就会关闭,CD 机也会自 动关机。同样的道理,Java 平台的作用就是执行 Java 程序代码。线程在执行完 main()方法 后,也就结束了。而当 Java 平台发现自己里面的线程都退出以后,也就会退出。这时 Java 程序就运行完毕了。 那么,线程是如何执行代码的呢?这个超出了本书的范围。就好像使用 CD 机一样, 使用者只要知道 CD 机中激光头是用来读取和处理 CD 碟片上的内容就可以了,没必要去 追究它是如何读取 CD 碟片上的内容的。对于线程也是一样的道理。前面说过,线程是操 作系统中的一个概念,所以“线程是如何执行程序的”这个问题属于操作系统课程中的内 容。对于学习 Java 而言,在这里先知道如下几点就可以了。 线程是执行 Java 程序代码的基本单位。 Java 线程也是 Java 平台的一部分。 Java 线程是运行在 Java 平台内部的,Java 平台负责管理 Java 线程。 Java 线程执行程序代码时,Java 平台为其提供各种所需的条件。 当线程执行完给它的方法后,就会退出。Java 平台中如果没有正在运行的线程, 就代表程序执行完毕,Java 平台也就自动退出了。 本节的内容就先到这里。本节中使用的“CD 机模型”比较容易理解,但是它和线程 还不是十分相似。在 15.1.2 节中将通过“演奏会模型”来加深对线程的理解。 15.1.2 演奏会模型 线程是隐藏在 Java 平台之中的,它的工作方式并没有展露在 Java 语法中。我们只能 够通过类比的方式来理解 Java 线程以及程序代码、Java 线程和 Java 平台三者之间的关系
第15章多线程编程 本节将要介绍的就是“演奏会模型”。演奏会并不是一个陌生的概念,可以把它看成是由 一个指挥家、一个或多个演奏家、乐谱组成的事物。它的最终结果就是演奏乐谱。我们的 这个演奏会模型与现实中的演奏会差不多,区别有以下几点。 口演奏会中使用的乐谱不是纸质的乐谱,而是用一个显示器显示乐谱。 口所有的乐谱都保存在一个存储设备上。所以在演奏会开始之前要先将乐谱输入到 存储设备中。 口每个演奏家使用一个单独的显示器来看乐谱,但是所有的显示器都从同一个存储 设备上读取乐谱。 口显示器每次只显示一小节乐谱内容,演奏家演奏完这个小节后,显示器会自动显 示出乐谱下一小节的内容,直到乐谱结束。 演奏会的工作模式也不同。 口首先将所有的乐谱输入到存储设备中。 口指挥家按照演奏的进度,每当需要演奏一个乐谱的时候,这个指挥家首先请上一 位演奏家,然后搬上一个显示器来显示需要演奏的乐谱。 口演奏家按照显示器上的内容进行演奏。当演奏家演奏完当前小节后,显示器自动 显示乐谱下一小节的内容。 口当乐谱结束后,演奏家就退场了。当所有的演奏家都退场以后,指挥家就退场, 演奏会就结束了。 1.Java线程和演奏会模型 下面用图15-4将Java程序和这个演奏会模型做一个类比。 Java源文件 乐谱源文件 Java的类文件 乐谱输入存储设备 后的数据 Java平台 指挥家 线程 演奏家 当前执行的程序 显示器当前显示的小节 图15-4Java线程和演奏会模型的类比 2.运行中的Java线程和演奏会模型 通过图15-4可以更清晰地看出线程、Java平台和程序代码之间的关系。一个演奏家专 心演奏摆在面前的乐谱,就好像Java线程一行行的执行代码。Java平台则是指挥家,管理 ·441▣
第 15 章 多线程编程 ·441· 本节将要介绍的就是“演奏会模型”。演奏会并不是一个陌生的概念,可以把它看成是由 一个指挥家、一个或多个演奏家、 乐谱组成的事物。它的最终结果就是演奏乐谱。我们的 这个演奏会模型与现实中的演奏会差不多,区别有以下几点。 演奏会中使用的乐谱不是纸质的乐谱,而是用一个显示器显示乐谱。 所有的乐谱都保存在一个存储设备上。所以在演奏会开始之前要先将乐谱输入到 存储设备中。 每个演奏家使用一个单独的显示器来看乐谱,但是所有的显示器都从同一个存储 设备上读取乐谱。 显示器每次只显示一小节乐谱内容,演奏家演奏完这个小节后,显示器会自动显 示出乐谱下一小节的内容,直到乐谱结束。 演奏会的工作模式也不同。 首先将所有的乐谱输入到存储设备中。 指挥家按照演奏的进度,每当需要演奏一个乐谱的时候,这个指挥家首先请上一 位演奏家,然后搬上一个显示器来显示需要演奏的乐谱。 演奏家按照显示器上的内容进行演奏。当演奏家演奏完当前小节后,显示器自动 显示乐谱下一小节的内容。 当乐谱结束后,演奏家就退场了。当所有的演奏家都退场以后,指挥家就退场, 演奏会就结束了。 1.Java线程和演奏会模型 下面用图 15-4 将 Java 程序和这个演奏会模型做一个类比。 图 15-4 Java 线程和演奏会模型的类比 2.运行中的Java线程和演奏会模型 通过图 15-4 可以更清晰地看出线程、Java 平台和程序代码之间的关系。一个演奏家专 心演奏摆在面前的乐谱,就好像 Java 线程一行行的执行代码。Java 平台则是指挥家,管理
第2篇Java语言高级语法 着整个程序,包括Java线程。Java平台为了让Java线程能够执行代码,做了很多的工作。 下面的图15-5将一个程序的执行过程和一个演奏会的执行过程做了一个类比。 将ava源文件编译灰lass文件 将乐谱输入存储设备 启ava平台 指挥家就绪 Java平台创建一个线程 指挥家请出一位演奏家 Java平台加载类文件,并找到 指挥家搬出一台显示器 其中的main(O方法 并让显示器显示需要演奏的乐谱 Java平台让这个线程从nainO方法执 指挥家让演奏家按照 行程序代码 显示器上的乐谱进行演奏 Java线程执行完上一行代码后,自 演奏家演奏完一小节以后,显示器 动执行下一行代码 显示下一小节,演奏家继续演奏 main(O方法结束,线程退出 乐谱演奏结束,演奏家退场 程序执行完毕,Java平台退出 演奏会演奏结束,指挥家退场 图15-5Java程序执行流程和演奏会流程 下面以一个简单的例程来说明图15-5中所示的流程。 package com.javaeasy.execution; //例程所在的包 public class Execution //例程名 public static void main(String[]args){ //main()方法,这就是程序执行 //的起点,也是线程执行的起点 int i 3+5; //第一行代码是一个运算操作 System.out.println(i); //第二行代码是一个方法调用 上面的例程很简单,这里不再解释。使用如下的javac命令对例程的源代码进行编译。 javac com\javaeasy\execution\Execution.java ·442·
第 2 篇 Java 语言高级语法 ·442· 着整个程序,包括 Java 线程。Java 平台为了让 Java 线程能够执行代码,做了很多的工作。 下面的图 15-5 将一个程序的执行过程和一个演奏会的执行过程做了一个类比。 图 15-5 Java 程序执行流程和演奏会流程 下面以一个简单的例程来说明图 15-5 中所示的流程。 package com.javaeasy.execution; // 例程所在的包 public class Execution { // 例程名 public static void main(String[] args) { // main()方法,这就是程序执行 // 的起点,也是线程执行的起点 int i = 3 + 5; // 第一行代码是一个运算操作 System.out.println(i); // 第二行代码是一个方法调用 } } 上面的例程很简单,这里不再解释。使用如下的 javac 命令对例程的源代码进行编译。 javac com\javaeasy\execution\Execution.java