当适当使用线程时,它可以减少开发和维护的开销,并能够提升复杂系统的性能。通过在顺序中是使用异步工作流线,模仿人类工作和交互变得更加简单。另外一方面,他们将复杂难以理解的代码转化为直接简单的代码,这样更加容易读写及维护。
线程在GUI应用中非常有用,提高用户界面响应速度,在服务器端,提高资源利用率和系统吞吐量。它们还可以简化jvm的实现,垃圾回收,通常运行于一个或者多个线程。在某种程度上,大部分重要的java应用依赖于线程来组织结构。
1.2.1 利用多处理器(Exploiting multiple processors)
在过去,多处理器系统很昂贵并且稀少,一般在大型数据中心和科学实验室才能够使用。如今,它们已经很便宜并且很普遍,甚至在低档的服务器和中层桌面系统都有多线程处理器,而且这种趋势还会加速;因为处理器很难提高它的时钟频率,取而代之的是,处理器供应商则通过在芯片上使用多处理器内核。所有的芯片供应商都开始向这种转变,我们已经看到了拥有多核心数的机器。
因为程序调度的基本单元室线程,只有一个线程的程序,在一个时刻,只能最多在一个处理器上运行,在两个处理器的系统上,单一线程程序放弃了使用另外一半可用的cpu资源;在一个100个处理器的系统,则要浪费99%,另外,多线程程序可以同时在多个处理器上执行。设计合理的话,多线程程序通过更高效利用处理器资源可以提高系统吞吐量。
使用多线程同样可以在单一处理器系统上提高系统吞吐量。如果一个程序是单线程的,当它同步等待i/o操作时,处理器处于休闲状态,在一个多线程程序,当第一个线程等待i/o完成时,其他线程可以继续运行,允许应用在i/o阻塞时继续处理任务。(这类似于在等待水煮沸的时候阅读报纸,而不是水煮开之后再开始阅读)。
1.2.2简单的建模
相比你有多种类型任务要执行时,执行只有一种类型任务的管理时间将更加简单。当你只有一种类型的任务要处理时,你可以从这堆的最上面开始,并一直执行直到这堆任务完成,你不用费心思下一步要做的任务;另外,管理多个优先级和截止时间,在任务间切换通常会附加一些开销。
这同样适用于软件,顺序处理一种类型的任务的程序更容易被开发,错误更少,测试更简单,和管理不同类型任务相比。给每种类型的任务或者在一个模型中给于顺序错觉并从调度明细、交叉操作、异步i/o和资源等待隔离逻辑域分配一个线程,一个复杂、异步工作流分别在独立的线程中运行,仅在指定同步的地方才会互相交互。
这个优点经常被用于框架中,如servlet,RMI(远程方法调用),这些框架处理请求管理、线程创建和负载平衡,将请求分发到在工作流合适的组件。Servlet作者不需要担心有多少其他请求同一时刻正在被处理,或者socket输入和输出是否阻塞。当一个servlet服务方法被调用用于响应一个web请求,它能够同步处理请求像单一程序一样,这可以简化组件开发和减少学习曲线成本。
1.2.3异步事件的简单处理
一个从多个远程客户端接收socket连接的应用服务器,每个连接都给于分配自己的线程来允许使用i/o同步,将会使开发变得更简单。
如果一个应用准备从一个socket中读数据,但切没有可用的数据时,read的操作将被阻塞直到有可用数据。在单线程应用,这将意味着不仅仅处理当前请求的响应停止了,其它所有请求的处理在这个线程阻塞的时候也都停止了。为了避免这个问题,单线程服务应用被强制使用非阻塞i/o,这相比同步i/o,将更加复杂而且容易出错。然而,每个请求都有自己的线程,然后阻塞不会影响其它请求的处理。
从历史上来看,操作系统限制较低数量的线程,一个进程会创建几百个甚至更少的线程数量。结果,操作系统开发有效的设备多路复用i/o,unix系统选择和轮询调用,访问这些设施,java类库有一系列的包(java.nio)来处理非阻塞i/o。然而,操作系统已经被重大提高而支持更大数量的线程,在一些平台,对大数量客户端使用每个客户端一个线程的模型。
1.2.4用户界面更好的响应性
图形用户界面曾用单线程,这意味着你必须要么频繁的从开始到结束不断轮询代码对于输入事件,要么间接通过“主事件轮询”执行所有应用代码。如果这代码从主事件轮询中被调用,则花更长时间来执行,用户界面似乎冻结状态直到完成执行代码,因为后续的用户界面事件不能被处理直到控制权被返回给主事件轮询。
现代的图形用户接口框架,如AWT和swing工具,用事件分发线程替代了主事件轮询 ,当一个用户界面事件,如按钮按下事件,应用预定义的处理在这事件线程中被调用,大部分图形用户界面框架是单线程子系统, 所有主事件轮询仍然有效存在,但是,它仅仅在图形用户界面工具的控制权下运行,而不是在应用当中。
如果在事件线程中仅有短暂的任务,那么这界面总能维持响应,因为事件线程总是可以合理快速处理用户活动,然而,在一个事件线程中处理一个长期任务,如在一个很大文档中校验拼音或者在网络中获取一个资源,会减慢响应,如果这个用户执行一个当作,当这个任务正在运行,那将会有一个很长的延迟,在这事件线程处理或者通知它之前。添加结果到问题处,不仅用户界面变得不能够响应,而且它不能撤销没用任务,即使用户界面提供一个取消按钮,因为事件线程正在忙,而且不能处理撤销事件直到漫长任务结束。然而,如果长期任务用一个独立线程来执行,这个事件线程保持休闲以来处理用户界面事件,是用户界面响应更加及时。