Java多线程编程核心技术(第3版)
上QQ阅读APP看书,第一时间看更新

1.1 进程和线程的定义及多线程的优点

本书主要介绍在Java语言中使用的多线程技术,但讲到多线程技术时不得不提及“进程”这个概念,百度百科里对“进程”的定义如图1-1所示。

图1-1 进程的定义

这段文字十分抽象,难以理解,那么再来看如图1-2所示的内容。

图1-2 Windows 7系统中的进程列表

难道一个正在操作系统中运行的exe程序就可以理解成一个“进程”?没错!

通过查看“Windows任务管理器”中的列表,完全可以将运行在内存中的exe文件理解成进程。进程是受操作系统管理的基本运行单元。

程序是指令序列,这些指令可以让CPU做指定的任务。*.java程序经编译后形成*.class文件。在IDE中运行*.class文件相当于在操作系统中启动一个JVM虚拟机进程,在该虚拟机进程中加载*.class文件并运行,*.class文件通过执行创建其他新线程的代码来执行具体的任务。

使用如下测试代码来验证运行一个class文件就是创建一个新的JVM虚拟机进程:


public class Test1 {
    public static void main(String[] args) {
        try {
            Thread.sleep(Integer.MAX_VALUE);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

在没有运行这个类之前,任务管理器中以j开头的进程列表如图1-3所示。

图1-3 任务管理器中以j开头的进程

图1-4 创建了3个javaw.exe进程

Test1类重复运行3次后的进程列表如图1-4所示。可以看到,在任务管理器中创建了3个javaw.exe进程,说明每运行1次*.class文件就创建一个javaw.exe进程,其本质上就是JVM虚拟机进程。

那什么是线程呢?线程可以理解为在进程中独立运行的子任务,比如QQ.exe运行时,很多子任务也同时在运行,如好友视频线程、下载文件线程、传输数据线程、发送表情线程等,这些不同的任务或者说功能都可以同时运行,其中每一项任务完全可以理解成是“线程”在工作,传文件、听音乐、发送图片表情等这些功能都有对应的线程在后台默默地运行。

进程负责向操作系统申请资源。在一个进程中,多个线程可以共享进程中相同的内存或文件资源。先有进程,后有线程。在一个进程中可以创建多个线程。

进程和线程的总结如下。

1)进程虽然是互相独立的,但它们可以互相通信,较为通用的方式是使用Socket或HTTP协议。

2)进程拥有共享的系统资源,比如内存、网络端口,供其内部线程使用。

3)进程较重,因为创建进程需要操作系统分配资源,会占用内存。

4)线程存在于进程中,是进程的一个子集,先有进程,后有线程。

5)虽然线程更轻,但线程上下文切换的时间成本非常高。

使用多线程有什么优点呢?其实如果大家有使用“多任务操作系统”的经验,比如Windows系列,那么对它的方便性应该都有体会:使用多任务操作系统Windows可以大幅利用CPU的空闲时间来处理其他任务,比如可以一边让操作系统处理正在用打印机打印的数据,一边使用Word编辑文档。CPU在这些任务中不停地切换,由于切换的速度非常快,给使用者的感受就是这些任务在同时运行,所以使用多线程技术可以在同一时间内做更多不同种类的任务。

为了更加有效地理解多线程的优势,下面先来看看单任务运行环境示意图,如图1-5所示。

图1-5 单任务运行环境

图1-6 多任务运行环境

如图1-5所示,任务1和任务2是两个完全独立、不相关的任务。任务1在等待远程服务器返回数据,以便进行后期处理,这时CPU一直处于等待状态,在“空运行”。任务2在10秒后运行,虽然执行任务2用的时间非常短,仅仅是1秒,但也必须等任务1运行结束后才可以运行,而且本程序是运行在单任务环境中,所以任务2的等待时间非常长,系统运行效率大幅降低。单任务的特点就是排队执行,也就是同步,就像在cmd中输入一条命令后,必须等待这条命令执行完才可以执行下一条命令一样。在同一时间只能执行一个任务,CPU利用率大幅降低,这就是单任务环境的缺点。

多任务运行环境如图1-6所示。

在图1-6中可以发现,CPU完全可以在任务1和任务2之间来回切换,使任务2不必等到10秒之后再运行,系统和CPU的运行效率大大提升,这就是为什么要使用多线程技术,为什么要学习多线程。多任务的特点是在同一时间内可以执行多个任务,这也是多线程技术的优点。使用多线程就是在使用异步。

在通常情况下,单任务与多任务的实现与操作系统有关,比如在一台电脑上使用同一个CPU,安装DOS磁盘操作系统只能实现单任务运行环境,而安装Windows操作系统则可以实现多任务运行环境。

在什么场景下使用多线程技术?笔者总结了两点。

1)阻塞:一旦系统中出现了阻塞现象,则可以根据实际情况来使用多线程提高运行效率。

2)依赖:业务分为两个执行过程,分别是A和B,当A业务有阻塞的情况发生时,B业务的执行不依赖A业务的执行结果,这时可以使用多线程来提高运行效率;如果B业务依赖A业务的执行结果,则不需要使用多线程技术,按顺序串行执行即可。

在实际的开发应用中,不要为了使用多线程而使用多线程,要根据实际场景决定。

注意

多线程是异步的,所以千万不要把IDE里代码的顺序当作线程执行的顺序,线程被调用的时机是随机的。