Java知识分享
热爱技术,分享技术

多线程设计模式之:通用Active Object框架模式

标准的ActiveObjects要将每一个方法都封装成Message(比如多线程设计模式之:Actvice Object设计模式定义的
FindOrderDetailsMessage, OrderMessage), 然后提交至Message队列中,这样的做法有点类似于远程方法调用( RPC : Remote Process Call)。

如果某个接口的方法很多,那么需要封装很多的Message类;同样如果有很多接口需要成为ActiveObject,则需要封装成非常多的Message类,这样显然不是很友好。在本节中,我们将设计一个更加通用的ActiveObject框架,可以将任意的接口转换成Active Object。


我们将使用JDK动态代理的方式实现一个更为通用ActiveObjects,可以将任意接口方法转换为Active Objects,当然如果接口方法有返回值,则必须要求返回Future类型才可以,否则将会抛出IllegalActiveMethod异常。

public class IllegalActiveMethod extends Exception {
public IllegalActiveMethod(String message){
super(message);
}
}

通用的Active Objects 设计消除了为每一个接口方法定义MethodMessage的过程,同时也摒弃掉了为每一个接口创建定义Proxy的实现,所有的操作都会被支持动态代理的工厂类ActiveServiceFactory所替代,通用Active Objects框架详细类图如图所示。

多线程设计模式之:通用Active Object框架模式插图

1. ActiveMessage详解

相比较于MethodMessage, ActiveMessage 更加通用,其可以满足所有Active Objects接口方法的要求,与MethodMessage类似,ActiveMessage也是用于收集接口方法信息和具体的调用方法的。ActiveMessage的代码如下。

package cn.hackcloud.concurrency.activeobjects;

import cn.hackcloud.concurrency.activeobject.ActiveFuture;
import cn.hackcloud.concurrency.future.Future;

import java.lang.reflect.Method;

class ActiveMessage {
//接口方法的参数
private final Object[] objects;
//接口方法
private final Method method;
//有返回值的方法,会返回ActiveFuture<?>类型
private final ActiveFuture<Object> future;
//具体的Service接口
private final Object service;

//构造ActiveMessage是由Builder 来完成的
ActiveMessage(Builder builder) {
this.objects = builder.objects;
this.method = builder.method;
this.future = builder.future;
this.service = builder.service;

}

//ActiveMessage的方法通过反射的方式调用执行的具体实现
public void execute() {
try {
//执行接口的方法
Object result = method.invoke(service, objects);
if (future != null) {
//如果是有返回值的接口方法,则需要通过get方法获得最终的结果
Future<?> realFuture = (Future<?>) result;
Object realResult = realFuture.get();
//将结果交给ActiveFuture,接口方法的线程会得到返回
future.finish(realResult);
}
} catch (Exception e) {
// 如果发生异常,那么有返回值的方法将会显式地指定结果为null, 无返回值的接口方法则会忽略该异常
if (future != null) {
future.finish(null);
}

}
}

static class Builder {
private Object[] objects;
private Method method;
private ActiveFuture<Object> future;
private Object service;

public Builder useMethod(Method method) {
this.method = method;
return this;
}

public Builder returnFuture(ActiveFuture<Object> future) {
this.future = future;
return this;
}

public Builder withObjects(Object[] objects) {
this.objects = objects;
return this;
}

public Builder forService(Object service) {
this.service = service;
return this;
}

//构建ActiveMessage实例
public ActiveMessage build() {
return new ActiveMessage(this);
}
}
}

构造ActiveMesage必须使用Builder方式进行build,其中包含了调用某个方法必需的人参( objects),代表该方法的java.ang.reflect.Method实例,将要执行的ActiveService实例(service), 以及如果该接口方法有返回值,需要返回的Future 实例(future)。

2. @ActiveMethod

通用的ActiveObjects更加灵活,它允许你将某个接口的任意方法转换为ActiveMethod,如果不需要转换,则需要按照普通方法来执行,而不会被单独的线程执行,要做到这一点,就需要使用@ActiveMethod注解来进行标记

package cn.hackcloud.concurrency.activeobjects;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface ActiveMethod {

}

比如,我们用@ActiveMethod标记前文中的OrderServicelmpl类,代码如下:
public class OrderServiceImpl implements OrderService
@ActiveMethod
@Override
public Future f indorderDetails (long orderId){


@ActiveMethod
@override
public void order ( String account, 1ong orderId){

}

3. ActiveServiceFactory详解

ActiveServiceFactory是通用Active Objects的核心类,其负责生成Service的代理以及构建ActiveMessage

package cn.hackcloud.concurrency.activeobjects;

import cn.hackcloud.concurrency.activeobject.ActiveFuture;
import cn.hackcloud.concurrency.activeobject.ActiveMessageQueue;
import cn.hackcloud.concurrency.future.Future;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class ActiveServiceFactory {
//定义ActiveMessageQueue, 用于存放ActiveMessage
private final static ActiveMessageQueue queue = new ActiveMessageQueue();

public static <T> T active(T instance) {
//生成Service的代理类
Object proxy = Proxy.newProxyInstance(instance.getClass().getClassLoader(),
instance.getClass().getInterfaces(), new ActiveInvocationHandler<>(instance));
return (T) proxy;
}

//ActiveInvocationHandler是InvocationHandler的子类,生成Proxy时需要使用到
private static class ActiveInvocationHandler<T> implements InvocationHandler {
private final T instance;

ActiveInvocationHandler(T instance) {
this.instance = instance;
}

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//如果接口方法被@ActiveMessage标记,则会转换为ActiveMessage
if (method.isAnnotationPresent(ActiveMethod.class)) {
//检查该方法是否符合规范
this.checkMethod(method);
ActiveMessage.Builder builder = new ActiveMessage.Builder();
builder.useMethod(method).withObjects(args).forService(instance);
Object result = null;
if (this.isReturnFutureType(method)) {
result = new ActiveFuture<>();
builder.returnFuture((ActiveFuture) result);
}
//将ActiveMessage加入至队列中
queue.offer(builder.build());
return result;
} else {
//如果是普通方法(没有使用@ActiveMethod标记),则会正常执行
return method.invoke(instance, args);
}
}

//检查有返回值的方法是否为Future, 否则将会抛出IllegalActiveMethod异常
private void checkMethod(Method method) throws IllegalActiveMethod {
//有返回值,必须是ActiveFuture类型的返回值
if (!isReturnVoidType(method) && !isReturnFutureType(method)) {
throw new IllegalActiveMethod("the method [" + method.getName()
+ " return type must be void/Future ");
}
}

//判断方法是否为Future返回类型
private boolean isReturnFutureType(Method method) {
return method.getReturnType().isAssignableFrom(Future.class);
}

//判断方法是否无返回类型
private boolean isReturnVoidType(Method method) {
return method.getReturnType().equals(Void.TYPE);


}
}
}
  • 静态方法active()会根据ActiveService实例生成一个动态代理实例,其中会用到ActiveInvocationHandler作为newProxyInstance的InvocationHandler。
  • 在ActiveInvocationHandler的invoke方法中,首先会判断该方法是否被@ActiveMethod标记,如果没有则被当作正常方法来使用。
  • 如果接口方法被@ActiveMethod标记,则需要判断方法是否符合规范:有返回类型,必须是Future类型。
  • 定义ActiveMessage.Builder分别使用method、方法参数数组以及Active Service实例,如果该方法是Future 的返回类型,则还需要定义ActiveFuture。
  • 口最后将ActiveMessage 插人ActiveMessageQueue中,并且返回method方法invoke结果。

4. ActiveMessageQueue及其他

插人到ActiveMessageQueue中的数据为MethodMessage,由于我们定义了更加通用的ActiveMessage,因此需要修改Queue中的数据类型

public class ActiveMessageQueue {
private final LinkedList<ActiveMessage> messageQueue = new LinkedList<>();

public ActiveMessageQueue() {
new ActiveDaemonThread(this).start();
}

public void offer(ActiveMessage message) {
synchronized (this) {
messageQueue.addLast(message);
//因为只有一个线程负责take数据,因此没有必要使用notifyAll方法
this.notify();
}
}

protected ActiveMessage take() {
synchronized (this) {
////当MethodMessage队列中没有Message的时候,执行线程进入阻塞
while (messageQueue.isEmpty()) {
try {
this.wait();
} catch (Exception e) {
e.printStackTrace();
}
}
//获取其中一个MethodMessage并且从队列中移除
return messageQueue.removeFirst();
}
}
}
/**
* ActiveDaemonThread是一个守护线程,主要是从queue中获取Message然后执行
* execute方法(注意:保持为线程命名的习惯是一个比较好的编程习惯)
*/
public class ActiveDaemonThread extends Thread {
private final ActiveMessageQueue queue;

public ActiveDaemonThread(ActiveMessageQueue queue) {
super("ActiveDaemonThread");
this.queue = queue;
setDaemon(true);
}

@Override
public void run() {
for (; ; ) {
ActiveMessage methodMessage = this.queue.take();
methodMessage.execute();
}
}
}

5. 总结

public static void main(String[] args) throws InterruptedException {
OrderService orderService = ActiveServiceFactory.active(new OrderServiceImpl());
Future<String> future = orderService.findOrderDetails(1000);
System.out.println("i will be returned immediately");
System.out.println(future.get());
}

运行上面的测试代码,future 将会立即返回,但是get方法会进入阻塞,10 秒钟以后订单的详细信息将会返回,同样, OrderService接口的调用线程和具体的执行线程不是同一个,
OrderServiceImpl通过active方法具备了可接受异步消息的能力。

我们通过System.gcO方法的原理分析,分别设计了两种不同的ActiveObjects模式实现,第二种方式更加通用一些,因为它摒弃了第- -种方式需要手动定义方法
的Message以及Proxy等缺陷,通过动态代理的方式动态生成代理类,当然读者可以通过开源的第三方Proxy来实现动态代理的功能,比如cglib以及asm等。


ActiveObjects模式既能够完整地保留接口方法的调用形式,又能让方法的执行异步化,这也是其他接口异步调用模式(Future模式:只提供了任务的异步执行方案,但是无法保留接口原有的调用形式)无法同时做到的。


Active Objects模式中使用了很多其他设计模式,代理类的生成(代理设计模
式)、ActiveMessageQueue ( Guarded Suspension Pattern 以及 Worker Thread Pattern )、findOrderDetails方法( Future设计模式),希望读者能够熟练掌握在Active Objects设计模式中用到的其他设计模式。

打赏
本站所有资源均来源于网络,仅供学习使用,请支持正版!Java技术开源 » 多线程设计模式之:通用Active Object框架模式

评论 抢沙发

评论前必须登录!

 

觉得文章有用就打赏一下文章作者

非常感谢你的打赏,我们将继续提供更多优质内容,让我们一起创建更加美好的网络世界!

支付宝扫一扫

微信扫一扫

登录

找回密码

注册