技术开发 频道

Active Object并发模式在Java 中的应用

  【IT168 技术】简介: Active Object 是并发编程实践中典型的设计模式,Active Object 模式的核心是通过解耦合方法的调用与执行来提高程序的并发度。本文将从典型 Active Object 设计模式入手,从一个新的视角来探讨 Active Object 并发模式在 Java 中的应用。

  本文主要从以下两个方面进行阐述:

  使用 C++ 语言,来描述 Active Object 设计模式。

  Java 类库对于这样一个典型的模式做了很好的类库层面的封装,因此对于 Java 的开发者来说,很多关于该设计模式本身的东西被屏蔽掉了。本文试图使用 Native C++ 语言,帮助读者从本质上对 Active Object 设计模式有一个更全面的认识。

  结合 C++ 版本的 Active Object 设计模式,引领读者对于 Active Object 设计模式在 Java 类库中的支持,有一个更深刻的认识,帮助读者正确并且有效地使用这些类库。

  预备知识

  并发对象 (Concurrent Object)

  在这里,我们先定义一下,什么是并发对象。不同于一般的对象,并发对象指的是该对象方法的调用与方法的执行不在同一个线程內,也即:该对象方法被异步执行。这其实是在多线程编程环境下典型的计算特征,线程引入了异步。从另一个角度来看,并发对象其实是面向对象的概念应用于多线程计算环境下的产物。

  Active Object 设计模式 C++ 描述

  我们将从以下几个方面来讨论 Active Object 模式。

  问题描述

  我们都知道,基于多线程机制的并发编程模式可以较高提升应用的 QoS(Quality of Service)。典型的例子如,我们在开发服务器端的应用时,通行的做法就是通过多线程机制并发地服务客户端提交上来的请求,以期提高服务器对客户端的反应度 (Responsiveness)。同时,相比于单线程的应用,并发的多线程应用相对要复杂得多。在多线程的计算环境里,并发对象被所有的调用者线程所共享。一般来说,并发对象的设计实现需要考虑下面的几个重要因素:

  并发对象的任何一次的方法执行,不允许无限地或者长时间阻止其它方法的调用执行,从而影响应用的 QoS。

  由于并发对象被调用者线程所共享,其内部状态必须保证是线程安全的,必须受限于某些线程同步约束,并且这些约束对调用者来说是透明的,不可见的。从调用者的角度来看,并发对象与普通对象没有多大区别。

  并发对象的设计实现,应该能够透明地利用底层平台所提供的并发机制。这样做的好处是,当并发对象运行在诸如多核处理器这类底层硬件平台上时,我们的应用能够充分挖掘底层平台带来的并发优势,以获得足够好的应用性能。

  我们使用 Active Object 设计模式来解决这些问题。

  Active Object 设计模式的本质是解耦合方法的调用 (Method invocation) 与方法的执行 (Method execution),方法调用发生在调用者线程上下文中,而方法的执行发生在独立于调用者线程的 Active Object 线程上下文中。并且重要的一点是,该方法与其它普通的对象成员方法对于调用者来说,没有什么特别的不同。从运行时的角度来看,这里涉及到两类线程,一个是调用者线程,另外一个是 Active Object 线程,我们会在下面更详细地谈到。

  结构

  在 Active Object 模式中,主要有以下几种类型的参与者:

  代理 (Proxy) :代理是 Active Object 所定义的对于调用者的公共接口。运行时,代理运行在调用者线程的上下文中,负责把调用者的方法调用转换成相应的方法请求 (Method Request),并将其插入相应的 Activation List,最后返回给调用者 Future 对象。

  方法请求:方法请求定义了方法执行所需要的上下文信息,诸如调用参数等。

  Activation List:负责存储所有由代理创建的,等待执行的方法请求。从运行时来看,Activation List 会被包括调用者线程及其 Active Object 线程并发存取访问,所以,Activation List 实现应当是线程安全的。

  调度者 (Scheduler):调度者运行在 Active Object 线程中,调度者来决定下一个执行的方法请求,而调度策略可以基于很多种标准,比如根据方法请求被插入的顺序 FIFO 或者 LIFO,比如根据方法请求的优先级等等。

  Servant: Servant 定义了 Active Object 的行为和状态,它是 Proxy 所定义的接口的事实实现。

  Future: 调用者调用 Proxy 所定义的方法,获得 Future 对象。调用者可以从该 Future 对象获得方法执行的最终结果。在真实的实现里,Future 对象会保留一个私有的空间,用来存放 Servant 方法执行的结果。

0