Java程序设计大学教程第十章 线程、文件与串行化本章将讨论有关线程及输入 /输出的一些高级话题。首先,讲述了线程和并发编程的基本概念、模型和应用;然后阐述怎样从文件中读取数据和将数据写入文件,其中包括
Java中最常见的输入 /输出流;最后介绍了对象串行化以及如何用对象流实现串行化。
Java程序设计大学教程
10.1 多线程程序设计
多线程程序能够使程序的不同部分同时运行。
现代操作系统和许多科学应用都是多线程程序。
使用多线程编程可以解决后台任务、并发操作、
管理用户界面等编程难题,多线程程序设计因此也越来越重要。
Java程序设计大学教程
10.1.1 多任务、进程和线程
在多任务操作系统中,通常一个运行的程序实例称为一个进程。进程也就是调入内存准备执行的程序。每个进程都在自己分配的空间内独立运行,进程与进程之间互不干扰。
线程是程序中的一个可执行语句序列,是一个单独的运行过程。通常,每个进程至少有一个线程(即主线程)在执行自己的地址空间中的代码。线程是进程内部执行的路径,
是操作系统分配 CPU时间的基本实体。
每个进程都可以包含多个线程,它们可以同时独立地执行进程的地址空间中的代码。进程的所有线程共享进程的地址空间。在基于线程的多任务处理环境中,线程是最小的执行单位。
Java程序设计大学教程
10.1.1 多任务、进程和线程应用程序为了实现多任务并行处理,可以采用创建多个进程和在单一进程中创建多线程两种方法,
但后者比前者更有效,这是因为:
线程是轻量级的任务,线程的代码已经映射到了进程的地址空间,而新进程的代码还需要载入内存,所以系统创建和执行线程要比创建和执行进程快得多;而进程是重量级的任务,需要更多的管理开销和系统资源。
进程的所有线程共享进程的地址空间,并能够访问进程的全局变量,因而线程之间的通信会更便捷,线程间的转换也是低成本的。
Java程序设计大学教程
10.1.2 Java线程模型当 Java程序运行时,立即启动一个主线程( main thread),
它由我们熟悉的 main方法开始执行。主线程可以起的作用是:
启动程序进程
负责创建其他子线程
负责完成整个进程最后的各种清理和关闭任务尽管主线程在程序启动时自动创建,但仍然可以通过
Thread.currentThread方法将其作为线程对象调用。要创建一个线程,可以通过实例化一个线程对象来实现。 Java给出了两种方式:
继承 Thread类
实现 Runnable接口
Java程序设计大学教程
10.1.2 Java线程模型
当 Java程序运行时,它由 main方法启动一个主线程。
而用 run方法启动一个子线程。对于新创建的线程。调用了该线程的 start方法之后,就会自动调用线程对象的
run方法。
线程是异步的,这就意味着执行的顺序和一系列线程的时序是零散而不可预测的,至少从编程者的角度看是这样的。
异步线程原则:除非它们是明确地有优先级的或者是严格同步的,否则线程是以完全异步的方式运行的。负责完成整个进程最后的各种清理和关闭任务。
多线程程序 MultiThreadDemo1运行演示。
Java程序设计大学教程
10.1.2 Java线程模型每个线程都有一个生命周期,它是由若干个不同的状态组成的。这些状态包括:
就绪 线程做好了运行准备并在等待 CPU
运行 线程在 CPU上执行
等待 线程在等待发生某个事件
休眠 线程已被告知要休眠一段时间
阻塞 线程在等待 I/O结束
死亡 线程被终止就绪运行死亡阻塞休眠等待
start()
notify()I/O结束超时
I/O请求
stopt() wait()
sleep()
notifyAll()
分派
Java程序设计大学教程
10.1.2 Java线程模型
线程休眠是线程的一种最重要的状态,它可以主动让出
CPU时间,消除资源竞争导致的阻塞。 Thread.sleep方法可以按照毫秒级的时间使线程保持休眠状态,从而允许其他等待着的线程运行。
理论上,优先级高的线程比优先级低的线程获得更多的 CPU时间。但实际上,线程获得的 CPU时间通常是由包括优先级在内的多种因素决定的。
要设置线程优先级,可用 Thread.setPriority方法。它将一个线程的优先级设置成一个整数值,该整数值在 1和 10之间。
协调两个线程之间的行为的一种方式是设定其中一个线程有更高的优先级。但一个永远都不放弃占有 CPU的高优先级线程会导致低优先级线程过度等待。
带优先级控制的多线程程序运行演示
( MultiThreadDemo3)
Java程序设计大学教程
10.1.3 设计多线程的应用程序
在 Java程序中,并发编程是通过多线程实现的。利用多线程编程的好处是能够让一个程序同时执行多个任务,这在设计动画时尤其重要。因为动画中通常有多个动画对象需要同时绘制,而不是等一个对象绘制完成后在绘制另一个对象。
多线程演示程序 BubbleThreadDemo的设计。
Java程序设计大学教程
10.2 流和文件
流指的是一种数据流。如果数据流写入程序中,那么该数据流称为输人流;相反,从程序中输出的数据流称为输出流。如果输入数据流来自键盘,则程序从键盘读取数据;如果输入数据流来自文件,则程序从文件读取数据。类似地,输出数据流则输出至文件或屏幕。
输入是指运行的程序从某个外部数据源读取信息或数据。当程序有输人数据时,它们或者来自键盘,或者来自 GUI界面中的组件(如 JTextField)。输出是指运行的程序将信息或数据写到某个外部目标中。当程序产生了输出,会被送到屏幕(控制台程序),GUI组件或文件中。
文件是保存在磁盘上或者其他持久性存储媒介上的数据集合。
文件的存在并不依赖于运行的程序。文件通过流实现输入和输出操作。
Java程序设计大学教程
10.2.1 基本概念
Java中的所有输入输出,无论它是文件 I/O还是涉及键盘和屏幕的 I/O,都是通过流的使用来完成的。一个流就是以另一个对象为源或目的地传送信息的对象。流就像一个管道,连通了信息的源及其目的地。
Java中有两种类型的文件:二进制文件和文本文件。这两种文件都将数据以位流序列的方式存储数据,即一个 0
或 1的序列。因此,这两种类型的文件之间的差别是读或写数据的程序对它们的不同解释。二进制文件是作为一个字节序列来处理的,而文本文件是作为一个字符序列来处理的。
文本文件可以用文本编辑器直接读写,而二进制文件不便使用文本编辑器直接读写,但却能够高效地由程序来进行读写。
Java程序设计大学教程
10.2.2 基于文本文件的应用
文本文件的格式文本文件由字符序列组成,这些字符被分成了行,并以特殊的文件结束符为结尾。当在文本编辑器中打开一个新文件时,它包含零行零个字符。输入了单个字符之后,
它将包含一个字符和一行。
读写文本文件输入流输 出 流
apple=n,苹果
face=n,脸
bee=n.蜜蜂
bed=n.床内存 文本文件
010000111
010001000
111010010
101011101
001010101
010000100
000001111
从一个文件中读数据:
1、把一个输入流连接到文件。
2、使用循环读取文本数据。
3、关闭流。
而向一个文件中写数据:
1、把一个输出流连接到文件。
2、在流里写入文本数据,
可能会使用循环来实现。
3、关闭流。
Java程序设计大学教程
10.2.3 I/O流与文件
Java提供了各种各样的 I/O流,这些流定义在 java.io包里。 I/O流可分为两大类,字节流和字符流。字节流
( byte stream)为处理字节的输入输出提供了方便;
而字符流多用于读写文本数据。但字节流来读写文件的效率最高,字节流通常用于对数据的底层处理上。
通常,二进制文件是由 InputStream和 OutputStream
的派生类处理的。而文本文件是由 Reader和 Writer的派生类处理的。
需要在给出文件名的情况下创建一个输出或输出流,并且希望能够向该文件中写入字符串,可选择
FileReader/FileWriter类,它们可用于读写文本文件。
Java程序设计大学教程
10.3 对象串行化
对象串行化也称为对象的序列化。对象串行化使得一个程序可以把一个完整的对象写到一个字节流里面;其逆过程则是从一个字节流里面读出一个事先存储在里面的完整的对象,称为对象的并行化。 Java串行处理功能真正强大之处在于一个 Java程序可以很容易地将一个 Java对象和一个二进制流之间相互转换。
对象串行化机制能自动弥补不同操作系统之间的差异;可以将对象的状态持久化保存;可以实现分布式对象;以及用于对象的
,深复制,。
Java对象串行化不仅保存了对象的全部信息,而且能追踪对象内所包含的所有引用,并保存那些对象;以此递归,形成一个对象网。递归串行化引用的对象时,Java对象串行化算法还自动维护串行化的对象引用表,防止发送同一引用对象的多个副本。
串行化通常可以自动完成,串行化时对象的所有数据成员都可串行化除了声明为 static的成员。对于不需要串行化的数据成员还可以通过 transient关键字将其强行屏蔽。
Java程序设计大学教程
10.3 对象串行化
在 Java中,实现了 java.io.Serializable接口的类对象可以串行化,不需要在类中增加任何代码。然而并不是每个类都可串行化的。
java.io包有两个串行化对象的流类。 ObjectOutputStream负责将对象写入字节流,ObjectInputStream从字节流读出对象。
对象 文件内存中临时存储 磁盘中持久存储储写出读入串行化并行化
ObjectOutputStream FileOnputStream
ObjectIutputStream FileInputStream