本文翻译自Java Concurrency / Multithreading Benefits

尽管多线程给程序实现带来了挑战,但由于多线程的一些优点我们仍然在使用它,其中的一些优点如下:

  • 更好的资源利用
  • 在某些场景可以简化程序设计
  • 提高程序响应

更好的资源利用

假设我们有一个程序从本地磁盘中读取和处理文件,若读取和处理一个文件的耗时分别为5秒钟和2秒钟,则读取处理2个文件的耗时如下:

1
2
3
4
5
6
5 seconds reading file A
2 seconds processing file A
5 seconds reading file B
2 seconds processing file B
-----------------------
14 seconds total//串行读取时总共耗时14秒

当从磁盘读取文件时CPU的大部分时间都花费在等待从磁盘读取数据,在此期间CPU大部分时间都处于空闲状态。这些空闲时间可以做一些其它的事情,通过改变操作顺序,CPU可以被更好的利用,如下面的列子:

1
2
3
4
5
5 seconds reading file A
5 seconds reading file B + 2 seconds processing file A
2 seconds processing file B
-----------------------
12 seconds total//并行读取时总共耗时12秒

在上面的例子中,CPU先等待读取第一个文件,然后开始读取第二个文件,在读取第二个文件的同时,CPU可以同时处理第一个文件。请记住,当等待从磁盘读取数据时,CPU大部分时间处于空闲状态!

通常情况下,CPU在等待IO响应时可以做一些其它事情,这不仅适用于磁盘IO操作,也适用于网络IO操作,或者读取用户输入,网络和磁盘IO操作通常比CPU和内存IO操作慢很多。

简化程序设计

如果在单线程应用程序中编程实现上述读取和处理文件的功能,就必须跟踪每个文件的读取和处理状态。相反的,在多线程程序中我们可以开启两个线程,每个线程读取和处理同一个文件。每个线程在等待从磁盘读取文件时都会被阻塞,但在等待的同时,其它线程可以利用CPU来处理已经读取的文件。这样能够是的CPU和磁盘都被更好的使用,而且由于每个线程只需要跟踪一个文件,编程实现也会变得更简单。

提高程序响应

将单线程应用变为多线程应用的另一个常见目的是获得更快的响应。假设有一个服务器程序在某个端口监听请求,当接收到一个请求后,服务器处理该请求,处理完后再继续监听,该循环监听服务器的设计草图如下:

1
2
3
4
while(server is active){
    listen for request //监听请求
    process request//处理请求
}

如果某个请求需要花费很长的时间来处理,那么在此期间其它的客户端就不能向此服务器发送请求,只有当服务器处于监听状态时才能够接收请求。

一种替代方案是让监听线程将接收到的请求发送给worker线程处理,然后立即恢复监听,worker线程对请求进行处理并给客户端发送回复,此种服务器的设计草图如下:

1
2
3
4
while(server is active){
    listen for request //监听请求
    hand request to worker thread//将接收到的请求发送给worker线程处理
}

在这种方式下,服务器线程会迅速返回监听,因而更多的客户端可以给服务器发送请求,服务器的响应也得以提高。

该方法同样适用于桌面应用程序,如果你点击一个按钮来开启一个长任务,而执行该任务的线程是更新窗口、按钮等部件的线程,那么在该任务运行期间,该桌面程序将无法响应其它操作。相反的,可以将该任务移交给一个worker线程,当worker线程处理该任务时,更新窗口的线程处于空闲状态,可以响应其它用户请求,当worker线程执行完任务时通知更新窗口线程,该窗口线程根据执行结果来更新程序。因而利用worker线程设计实现的程序对用户更具有响应性。

<–翻译结束!–>