这些Java教程是针对JDK 8编写的。本页面中描述的示例和实践不利用后续版本中引入的改进,并且可能使用不再可用的技术。
请参阅Java语言更改以了解Java SE 9及后续版本中更新的语言功能的概要。
请参阅JDK发行说明以获取有关所有JDK版本的新功能、增强功能以及已删除或弃用选项的信息。
计算引擎的核心是一种协议,它使得任务可以提交给计算引擎,计算引擎可以运行这些任务,并将任务的结果返回给客户端。这个协议通过计算引擎支持的接口来表达。下图显示了该协议的远程通信。
每个接口包含一个方法。计算引擎的远程接口Compute
允许将任务提交到引擎。客户端接口Task
定义了计算引擎执行提交任务的方式。
接口定义了远程可访问的部分,即计算引擎本身。下面是compute.Compute
Compute
接口的源代码:
package compute; import java.rmi.Remote; import java.rmi.RemoteException; public interface Compute extends Remote { <T> T executeTask(Task<T> t) throws RemoteException; }
通过扩展java.rmi.Remote
接口,Compute
接口将自身标识为可以从另一个Java虚拟机调用方法的接口。实现这个接口的任何对象都可以是远程对象。
作为远程接口的成员,executeTask
方法是一个远程方法。因此,该方法必须被定义为能够抛出java.rmi.RemoteException
异常。这个异常在远程方法调用时由RMI系统抛出,表示发生了通信故障或协议错误。RemoteException
是一个受检异常,因此调用远程方法的任何代码都需要通过捕获或在throws
子句中声明来处理这个异常。
计算引擎所需的第二个接口是Task
接口,它是Compute
接口中executeTask
方法的参数类型。
接口定义了计算引擎和需要执行的工作之间的接口,提供了启动工作的方式。下面是compute.Task
Task
接口的源代码:
package compute; public interface Task<T> { T execute(); }
Task
接口定义了一个名为execute
的方法,该方法没有参数,也不抛出任何异常。因为该接口没有扩展Remote
接口,所以该接口中的方法不需要在其throws
子句中列出java.rmi.RemoteException
。
Task
接口有一个类型参数T
,代表任务计算的结果类型。这个接口的execute
方法返回计算的结果,因此它的返回类型是T
。
Compute
接口的executeTask
方法返回传递给它的Task
实例的执行结果。因此,executeTask
方法有它自己的类型参数T
,将自己的返回类型与传递的Task
实例的结果类型关联起来。
RMI使用Java对象序列化机制在Java虚拟机之间传输对象。要使一个对象可序列化,它的类必须实现java.io.Serializable
标记接口。因此,实现Task
接口的类也必须实现Serializable
接口,任务结果的类也必须实现Serializable
接口。
Compute
对象可以运行不同种类的任务,只要它们是Task
类型的实现。实现这个接口的类可以包含计算任务所需的任何数据,以及计算所需的其他方法。
这就是RMI使这个简单的计算引擎成为可能的方式。因为RMI可以假设Task
对象是用Java编程语言编写的,之前对计算引擎未知的Task
对象的实现会在需要时由RMI下载到计算引擎的Java虚拟机中。这种能力使计算引擎的客户端能够定义在服务器上运行的新类型的任务,而不需要将代码显式安装在该机器上。
计算引擎由ComputeEngine
类实现,它实现了Compute
接口,通过调用其executeTask
方法可以提交不同的任务给它。这些任务使用任务的execute
方法来运行,并将结果返回给远程客户端。