多线程优势

521 阅读5分钟

原文:tutorials.jenkov.com/java-concur…

多线程最明显的优势是:

  • 更好的利用CPU
  • 更加简化某些情况下的设计
  • 更好的程序响应
  • 更公平地为不同任务进行CPU资源分配

更好的利用CPU

设想一个程序读取和处理本地文件系统的文件,假设从磁盘中读取一个文件需要花费5秒,处理一个文件需要花费2秒,那么处理两个文件需要花费

 5 seconds reading file A
 2 seconds processing file A
 5 seconds reading file B
 2 seconds processing file B
-----------------------
 14 seconds total

当从磁盘中读取文件时,绝大部分的CPU时间花费在等待磁盘读取数据。那会CPU十分空闲,其实它是可以干点其他事的。通过改变操作的顺序,CPU能够得到更充分的利用,看下面的顺序:

 5 seconds reading file A
 5 seconds reading file B + 2 seconds processing file A
 2 seconds processing file B
-----------------------
 12 seconds total

CPU等待读取第一个文件,然后开始读取第二个文件,当等待IO组件读取第二个文件时,CPU处理第一个文件。记住,当从磁盘读取文件时,CPU大部分时间是空闲的。

译者注:显然这个例子是基于阻塞IO来说的,我们知道在阻塞IO中,线程在执行read方法时会被阻塞,如果不使用多线程,那么在读取第二个文件时,无法处理第一个文件,因为读取第二个文件的线程被阻塞了。如果我的理解有问题还希望大家指正

译者注:作者说的一个线程应该不是指一台机器只有一个线程,而是只为该程序分配一个线程。可即使这样,如何才能在一个线程下实现上述顺序?

总的来说,当等待IO操作时CPU可以进行其他操作。这个IO不一定非得是磁盘IO,也可以是网络IO,或者等待用户的输入。网络和磁盘IO要比CPU和内存的IO要慢很多。

更简约的程序设计

如果你想要在单线程应用总手动实现上述顺序的读取和处理操作,你不得不同时跟踪每个文件的读取和处理状态。然而,你可以启动两个线程,每个线程只负责一个文件的读取和处理。当这两个线程在读取文件被阻塞时,其他线程可以利用CPU去处理已经读取的数据,这样一来,磁盘就总会保持忙碌状态,把数据从多个文件读到内存中。从而保证磁盘和CPU得到更充分的利用,而且对程序来说也简单,每个线程只跟踪自己的文件。

译者注:不太明白作者说的手动是什么意思,既然是单线程应用,线程在执行read时肯定会被阻塞,也就是说当读取第二个文件被阻塞时,没有其他线程来处理第一个文件,那怎么实现上述处理顺序呢?在此也希望大家帮忙解惑 译者注:

更好的程序响应

将单线程应用变为多线程应用的另一个目的是获得更好的响应。设想有个服务器端程序监听在某个端口以接受请求,当收到请求时,它会处理该请求然后返回继续监听,服务器端的循环大体如下:

while(server is active){
    listen for request
    process request
  }

如果处理这个请求需要花费很长时间,那么其他客户端在这段时间内将无法发送请求,只有当服务器处在监听状态时才能接受请求。

一种替代设计是监听线程将请求交给工作者线程,然后立即返回。设计大体如下:

while(server is active){
    listen for request
    hand request to worker thread
  }

这种方式使得服务器端线程快速返回到监听状态,因此更多的客户端可以发送请求。这台服务器变得更具响应性。

对于桌面程序也是如此,如果你点击一个按钮,以此触发一个长时任务,一旦执行任务的线程跟更新窗口,按钮等是一个线程,那么在执行长时任务时应用程序将变得无法响应。相反,可以将任务交一个工作者线程,当工作者线程处理任务时,窗口线程可以很好的接受其他用户的请求。一旦工作者线程完成任务,它会给窗口线程发送信号,然后窗口线程根据任务结果更新窗口。工作者线程使得应用程序更具响应性。

更公平的CPU资源分配

设想有一台服务器接收客户端请求,并且其中一个请求的处理比较耗时,例如10秒。如果这台服务器使用一个线程处理所有请求,那么对该请求后面的其他请求的处理将被拖慢,直到这个请求处理完。通过多线程划分CPU时间以及多线程的切换,可以让CPU在多个请求之间更公平地共享执行时间。那么即使一个请求处理比较慢,那么其他可更快处理的请求可以跟这个请求并发执行。当然,对慢请求的处理会变得更慢,因为它不会再独占CPU来执行,但是其他请求却等待更短的时间,因为没有必要等待这个慢请求处理完。到最后,只有这个慢任务在运行,CPU仍然可以单独分配给该任务来执行。


下一篇:多线程开销