3.1 执行器简介

第2章已经介绍过,Java实现并发应用程序的基本机制如下。

  • 实现了Runnable接口的类:这是要以并发方式实现的代码。
  • Thread类的一个实例:这是将以并发方式执行该代码的线程。

这种方式可以创建并管理Thread对象,并且实现线程间的同步机制。然而,这也会带来一些问题,尤其对那些具有大量并发任务的应用程序来说更是如此。如果线程太多,就会降低应用程序性能,甚至会使整个系统中断运行。

Java 5引入了执行器框架解决这些问题,并且提供了一个高效的解决方案,相对于传统并发机制而言,该解决方案更便于编程人员使用。

在本章中,我们将通过实现如下两个使用执行器框架的例子,介绍该框架的基本特征。

  • k-最近邻算法:这是一种用于分类的基本机器学习算法。它基于训练数据集中k个与测试范例标签最相似的范例确定测试范例的标签。
  • 客户端/服务器环境下的并发处理:当前,能够将信息提供给成千上万个客户端的应用程序非常重要,采用最佳方式实现系统的服务器端非常必要。

第4章和第5章将介绍执行器的更多高级特性。

3.1.1 执行器的基本特征

执行器的主要特征如下。

  • 不需要创建任何Thread对象。如果要执行一个并发任务,只需要创建一个执行该任务(例如一个实现Runnable接口的类)的实例并且将其发送给执行器。执行器会管理执行该任务的线程。
  • 执行器通过重新使用线程来缩减线程创建带来的开销。在内部,执行器管理着一个线程池,其中的线程称为工作线程(worker-thread)。如果向执行器发送任务而且存在某一空闲的工作线程,那么执行器就会使用该线程执行任务。
  • 使用执行器控制资源很容易。可以限制执行器工作线程的最大数目。如果发送的任务数多于工作线程数,那么执行器就会将任务存入一个队列。当工作线程完成某个任务的执行后,将从队列中调取另一个任务继续执行。
  • 你必须以显式方式结束执行器的执行,必须告诉执行器完成执行之后终止所创建的线程。如若不然,执行器则不会结束执行,这样应用程序也不会结束。

执行器还有一些更有用的特征,使其更加强大、灵活。

3.1.2 执行器框架的基本组件

执行器框架中含有各种接口和类,它们可实现执行器提供的全部功能。该框架的基本组件如下。

  • Executor接口:这是Executor框架的基本接口。它仅定义了一个方法,即允许编程人员向执行器发送一个Runnable对象。
  • ExecutorService接口:该接口扩展了Executor接口并且包括更多方法,增加了该框架的功能,例如以下所述。
    • 执行可返回结果的任务:Runnable接口提供的run()方法并不会返回结果,但是借用执行器,任务可以返回结果。
    • 通过单个方法调用执行一个任务列表。
    • 结束执行器的执行并且等待其终止。
  • ThreadPoolExecutor类:该类实现了Executor接口和ExecutorService接口。此外,它还包含一些其他获取执行器状态(工作线程的数量、已执行任务的数量等)的方法、确定执行器参数(工作线程的最小和最大数目、空闲线程等待新任务的时间等)的方法,以及支持编程人员扩展和调整其功能的方法。
  • Executors类:该类为创建Executor对象和其他相关类提供了实用方法。