Java 中的 Active Object 模式:实现高效异步处理
Active Object 设计模式的意图
Active Object 模式为 Java 中的异步处理提供了一种可靠的方法,确保应用程序响应迅速并高效地管理线程。它通过将任务封装在具有自身线程和消息队列的对象中来实现这一点。这种分离使主线程保持响应,并避免直接线程操作或共享状态访问等问题。
Active Object 模式的详细解释,包括现实世界的例子
现实世界的例子
想象一家繁忙的餐厅,顾客向服务员点餐。服务员不是自己去厨房准备食物,而是将订单写在单子上交给了调度员。调度员管理着厨师池,厨师异步地准备餐点。一旦有厨师空闲,他们就会从队列中取出下一个订单,准备菜肴,并在菜肴准备好后通知服务员。
在这个比喻中,服务员代表客户端线程,调度员代表调度器,厨师代表在独立线程中执行方法。这种设置允许服务员继续接单,而不会被食物准备过程阻塞,就像 Active Object 模式将方法调用与执行解耦以增强并发性一样。
通俗地说
Active Object 模式将方法执行与方法调用解耦,以提高多线程应用程序的并发性和响应能力。
维基百科说
active object 设计模式将方法执行与方法调用解耦,每个对象都驻留在其自己的控制线程中。[1] 目标是通过使用异步方法调用和用于处理请求的调度器来引入并发性。
该模式包含六个元素
- 代理,它为客户端提供一个带有公开访问方法的接口。
- 一个定义了对 active object 的方法请求的接口。
- 来自客户端的待处理请求列表。
- 调度器,它决定接下来执行哪个请求。
- active object 方法的实现。
- 供客户端接收结果的回调或变量。
Java 中 Active Object 的编程示例
本节介绍了 Active Object 设计模式在 Java 中的工作原理,强调了它在异步任务管理和并发控制中的使用。
兽人以其野性和难以驯服的灵魂而闻名。从过去的行为来看,它们似乎有自己的控制线程。为了实现一个具有自己的控制线程机制并仅公开其 API 而不是执行本身的生物,我们可以使用 Active Object 模式。
public abstract class ActiveCreature {
private final Logger logger = LoggerFactory.getLogger(ActiveCreature.class.getName());
private BlockingQueue<Runnable> requests;
private String name;
private Thread thread;
public ActiveCreature(String name) {
this.name = name;
this.requests = new LinkedBlockingQueue<Runnable>();
thread = new Thread(new Runnable() {
@Override
public void run() {
while (true) {
try {
requests.take().run();
} catch (InterruptedException e) {
logger.error(e.getMessage());
}
}
}
}
);
thread.start();
}
public void eat() throws InterruptedException {
requests.put(new Runnable() {
@Override
public void run() {
logger.info("{} is eating!", name());
logger.info("{} has finished eating!", name());
}
}
);
}
public void roam() throws InterruptedException {
requests.put(new Runnable() {
@Override
public void run() {
logger.info("{} has started to roam the wastelands.", name());
}
}
);
}
public String name() {
return this.name;
}
}
我们可以看到,任何扩展 ActiveCreature
类的类都将拥有自己的控制线程来调用和执行方法。
例如,Orc
类
public class Orc extends ActiveCreature {
public Orc(String name) {
super(name);
}
}
现在,我们可以创建多个生物,例如兽人,告诉它们吃东西和四处游荡,它们将在自己的控制线程上执行这些操作。
public class App implements Runnable {
private static final Logger logger = LoggerFactory.getLogger(App.class.getName());
private static final int NUM_CREATURES = 3;
public static void main(String[] args) {
var app = new App();
app.run();
}
@Override
public void run() {
List<ActiveCreature> creatures = new ArrayList<>();
try {
for (int i = 0; i < NUM_CREATURES; i++) {
creatures.add(new Orc(Orc.class.getSimpleName() + i));
creatures.get(i).eat();
creatures.get(i).roam();
}
Thread.sleep(1000);
} catch (InterruptedException e) {
logger.error(e.getMessage());
Thread.currentThread().interrupt();
} finally {
for (int i = 0; i < NUM_CREATURES; i++) {
creatures.get(i).kill(0);
}
}
}
}
程序输出
09:00:02.501 [Thread-0] INFO com.iluwatar.activeobject.ActiveCreature -- Orc0 is eating!
09:00:02.501 [Thread-2] INFO com.iluwatar.activeobject.ActiveCreature -- Orc2 is eating!
09:00:02.501 [Thread-1] INFO com.iluwatar.activeobject.ActiveCreature -- Orc1 is eating!
09:00:02.504 [Thread-0] INFO com.iluwatar.activeobject.ActiveCreature -- Orc0 has finished eating!
09:00:02.504 [Thread-1] INFO com.iluwatar.activeobject.ActiveCreature -- Orc1 has finished eating!
09:00:02.504 [Thread-0] INFO com.iluwatar.activeobject.ActiveCreature -- Orc0 has started to roam in the wastelands.
09:00:02.504 [Thread-2] INFO com.iluwatar.activeobject.ActiveCreature -- Orc2 has finished eating!
09:00:02.504 [Thread-1] INFO com.iluwatar.activeobject.ActiveCreature -- Orc1 has started to roam in the wastelands.
09:00:02.504 [Thread-2] INFO com.iluwatar.activeobject.ActiveCreature -- Orc2 has started to roam in the wastelands.
何时在 Java 中使用 Active Object 模式
在以下情况下,在 Java 中使用 Active Object 模式
- 当您需要处理异步任务而不会阻塞主线程时,确保更好的性能和响应能力。
- 当您需要异步地与外部资源交互时。
- 当您希望提高应用程序的响应能力时。
- 当您需要以模块化和可维护的方式管理并发任务时。
Active Object 模式 Java 教程
Java 中 Active Object 模式的现实世界应用
- 实时交易系统,其中交易请求以异步方式处理。
- GUI,其中长时间运行的任务在后台执行,而不会冻结用户界面。
- 游戏编程,以处理对游戏状态或 AI 计算的并发更新。
Active Object 模式的优点和权衡
了解在 Java 中使用 Active Object 模式的优缺点,包括提高线程安全性以及潜在的开销问题。
优点
- 提高主线程的响应能力。
- 将并发问题封装在对象中。
- 促进更好的代码组织和可维护性。
- 提供线程安全性,避免共享状态访问问题。
权衡
- 由于消息传递和线程管理而引入额外的开销。
- 可能不适合所有类型的并发问题。
相关的 Java 设计模式
- 命令:将请求封装为对象,类似于 Active Object 模式封装方法调用。
- 承诺:提供一种方法来检索异步方法调用的结果,通常与 Active Object 一起使用。
- 代理:Active Object 模式可以使用代理来异步地处理方法调用。