现在我们已经知道active object模式的核心思想,也明白了如何自己写一段实现类似效果的java代码。现在我们按照active object模式的角色分工,将第二篇中的例子重新实现下,参考了Active Object并发模式在Java中的应用 这篇博客。在 Active Object 模式中,主要有以下几种类型的参与者:
- 代理 (proxy) :代理是 Active Object 所定义的对于调用者的公共接口。运行时,代理运行在调用者线程的上下文中,负责把调用者的方法调用转换成相应的方法请求 (Method Request),并将其插入相应的 Activation List,最后返回给调用者 Future 对象。代理角色具有以下几个特点:
1.proxy和servant有着相同的接口签名,或者proxy比servant接口更简单好用。这样可以方便调用者无差别的对待proxy和servant,或者更容易使用代理
2.创建client需要的future对象,并快速返回,避免调用者线程长时间等待.客户端可以通过future对象获取实际的运算结果
3.将调用者的方法调用转换成相应的方法请求 (Method Request),将request和servant传给scheduler进行调度执行
4.代理是运行在调用者线程中的,它对原始的耗时服务进行了封装,让客户端无差异的使用代理和真实对象,除了更快.
2.创建client需要的future对象,并快速返回,避免调用者线程长时间等待.客户端可以通过future对象获取实际的运算结果
3.将调用者的方法调用转换成相应的方法请求 (Method Request),将request和servant传给scheduler进行调度执行
4.代理是运行在调用者线程中的,它对原始的耗时服务进行了封装,让客户端无差异的使用代理和真实对象,除了更快.
- 方法请求(method request):方法请求定义了方法执行所需要的上下文信息,诸如调用参数等。
- activation list:负责存储所有由代理创建的,等待执行的方法请求。从运行时来看,Activation List 会被包括调用者线程及其 Active Object 线程并发存取访问,所以,Activation List 实现应当是线程安全的。
- 调度者 (scheduler):调度者运行在 Active Object 线程中,调度者来决定下一个执行的方法请求,而调度策略可以基于很多种标准,比如根据方法请求被插入的顺序 FIFO 或者 LIFO,比如根据方法请求的优先级等等。
- servant::Servant 定义了 Active Object 的行为和状态,它是 Proxy 所定义的接口的事实实现。
- future:调用者调用 Proxy 所定义的方法,获得 Future 对象。调用者可以从该 Future 对象获得方法执行的最终结果。在真实的实现里,Future 对象会保留一个私有的空间,用来存放 Servant 方法执行的结果。
我们现在先编写servant类,这个是整个active object角色中最简单的
package activeobject.aty.servant;
import activeobject.aty.result.WeatherResult;
//Servant 的实现是纯粹的应用逻辑实现,或者称为商业逻辑实现,没有混合任何的线程同步机制 , 这有利于我们进行应用逻辑的重用,而不需要考虑不同的线程同步机制。
public class WeatherServant
{
public WeatherResult getWeatherInfo(String city, String day)
{
try
{
// 模拟耗时操作,调用该方法的线程,要挂起5s
Thread.sleep(5 * 1000);
}
catch (InterruptedException e)
{
}
WeatherResult result = new WeatherResult();
result.setTemperature(28);
result.setWindDirection("西北风");
result.setDampness("74%");
return result;
}
}
package activeobject.aty.result;
// 模拟天气预报的查询结果
//今日天气实况:气温:4℃;风向/风力:西北风 1级;湿度:74%;空气质量:中;紫外线强度:最弱
public class WeatherResult
{
// 气温
private int temperature;
// 湿度
private String dampness;
// 风向
private String windDirection;
public int getTemperature()
{
return temperature;
}
public void setTemperature(int temperature)
{
this.temperature = temperature;
}
public String getDampness()
{
return dampness;
}
public void setDampness(String dampness)
{
this.dampness = dampness;
}
public String getWindDirection()
{
return windDirection;
}
public void setWindDirection(String windDirection)
{
this.windDirection = windDirection;
}
@Override
public String toString()
{
return "WeatherResult [temperature=" + temperature + ", dampness=" + dampness + ", windDirection="
+ windDirection + "]";
}
}
现在编写methodrequest和future代码
package activeobject.aty.future;
import activeobject.aty.result.WeatherResult;
// 调用者调用 Proxy 所定义的方法,获得 Futur 对象。调用者可以从该 Future 对象获得方法执行的最终结果。
// 在真实的实现里,Future 对象会保留一个私有的空间,用来存放 Servant 方法执行的结果。
public class WeatherFuture
{
private boolean isDone = false;
private WeatherResult result = null;
public WeatherResult get()
{
while (!isDone)
{
}
return result;
}
public void setDone(boolean isDone)
{
this.isDone = isDone;
}
public void setResult(WeatherResult result)
{
this.result = result;
}
}
package activeobject.aty.methodrequest;
import activeobject.aty.future.WeatherFuture;
import activeobject.aty.result.WeatherResult;
import activeobject.aty.servant.WeatherServant;
// Method Request:方法请求定义了方法执行所需要的上下文信息,诸如调用参数、返回结果和实际的服务等
public class WeatherMethodRequest
{
private WeatherFuture future;
private WeatherServant servant;
private String city;
private String day;
public WeatherMethodRequest(WeatherFuture future, WeatherServant servant, String city, String day)
{
this.future = future;
this.servant = servant;
this.city = city;
this.day = day;
}
public void call()
{
WeatherResult result = servant.getWeatherInfo(city, day);
future.setResult(result);
future.setDone(true);
}
}
下面编写activation list
package activeobject.aty.activationlist;
import java.util.ArrayList;
import java.util.List;
import activeobject.aty.methodrequest.WeatherMethodRequest;
// Activation List 负责存储所有由代理创建的,等待执行的方法请求。
// 从运行时来看,Activation List 会被包括调用者线程及其 Active Object线程并发存取访问,所以Activation List 实现应当是线程安全的.
// Activation List 的实际上就是一个线程同步机制保护下的 Method Request队列,对该队列的所有操作 (insert/remove)都应该是线程安全的。
// 从本质上讲,Activation List 所基于的就是典型的生产者 / 消费者并发编程模型,调用者线程作为生产者把
// Method Request放入该队列,Active Object 线程作为消费者从该队列拿出 Method Request, 并执行。
public class WeatherActivationList
{
private List<WeatherMethodRequest> requestList = new ArrayList<WeatherMethodRequest>();
public synchronized void insertTask(WeatherMethodRequest request)
{
requestList.add(request);
}
public synchronized void removeTask(WeatherMethodRequest request)
{
requestList.remove(request);
}
public synchronized boolean isEmpty()
{
return requestList.size() == 0;
}
public synchronized WeatherMethodRequest popFirst()
{
WeatherMethodRequest e = requestList.get(0);
requestList.remove(0);
return e;
}
}
到这里我们的请求已经在activation list中了,我们可以基于activation list编写我们的scheduler实现
package activeobject.aty.scheduler;
import activeobject.aty.activationlist.WeatherActivationList;
import activeobject.aty.methodrequest.WeatherMethodRequest;
// Active Object 的线程
public class WeatherStartThread implements Runnable
{
private WeatherActivationList safeRequestList;
public WeatherStartThread(WeatherActivationList safeRequestList)
{
this.safeRequestList = safeRequestList;
}
@Override
public void run()
{
while (true)
{
if (!safeRequestList.isEmpty())
{
WeatherMethodRequest request = safeRequestList.popFirst();
request.call();
}
}
}
}
package activeobject.aty.scheduler;
import activeobject.aty.activationlist.WeatherActivationList;
import activeobject.aty.methodrequest.WeatherMethodRequest;
// scheduler:调度者运行在 Active Object线程中,调度者来决定下一个执行的方法请求,
// 而调度策略可以基于很多种标准,比如根据方法请求被插入的顺序 FIFO 或者 LIFO,比如根据方法请求的优先级等等。
public class WeatherTaskScheduler
{
private WeatherActivationList safeRequestList = new WeatherActivationList();
public WeatherTaskScheduler()
{
new Thread(new WeatherStartThread(safeRequestList)).start();
}
public void insertRequest(WeatherMethodRequest methodRequest)
{
safeRequestList.insertTask(methodRequest);
}
}
下面我们来编写代理类的实现,这个是客户端直接使用的类
package activeobject.aty.proxy;
import activeobject.aty.future.WeatherFuture;
import activeobject.aty.methodrequest.WeatherMethodRequest;
import activeobject.aty.scheduler.WeatherTaskScheduler;
import activeobject.aty.servant.WeatherServant;
//代理 (Proxy)负责以下功能:
// 1.proxy和servant有着相同的接口签名,或者proxy比servant接口更简单好用。这样可以方便调用者无差别的对待proxy和servant,或者更容易使用代理
// 2.创建client需要的future对象,并快速返回,避免调用者线程长时间等待.客户端可以通过future对象获取实际的运算结果
// 3.将调用者的方法调用转换成相应的方法请求 (Method Request),将request和servant传给scheduler进行调度执行
// 4.代理是运行在调用者线程中的,它对原始的耗时服务进行了封装,让客户端无差异的使用代理和真实对象,除了更快.
public class WeatherProxy
{
// 对任务进行调度
private static WeatherTaskScheduler scheduler = new WeatherTaskScheduler();
// 服务的真正实现
private static WeatherServant servant = new WeatherServant();
public static WeatherFuture getWeatherInfo(String city, String day)
{
WeatherFuture futureResult = new WeatherFuture();
WeatherMethodRequest request = new WeatherMethodRequest(futureResult, servant, city, day);
scheduler.insertRequest(request);
return futureResult;
}
}
最后我们编写测试类,来验证我们的功能。
package activeobject.aty;
import activeobject.aty.future.WeatherFuture;
import activeobject.aty.proxy.WeatherProxy;
import activeobject.aty.result.WeatherResult;
public class TestWeather {
public static void main(String[] args) throws Exception {
mockMultiCall();
testAsyncCall();
}
public static void testAsyncCall() throws Exception {
// 1.调用天气计算服务,开始计算深圳的天气情况(开始计算)
WeatherFuture future = WeatherProxy
.getWeatherInfo("广东深圳", "2014-03-14");
// 2.后台在计算天气服务中.当前线程没有阻塞,仍然可以继续执行.
System.out.println("After calling weather service,i am still running.");
// 3.The current thread is not blocked, do something else here...
// Thread.sleep(5 * 1000);
// 4.与天气计算结果无关的代码执行完毕.
System.out.println("Now,i really need weather result to continue.");
// 5.如果计算天气还没有结束,那么当前线程挂起,等候计算完成.
WeatherResult info = future.get();
System.out.println("天气查询结果:" + info);
}
public static void mockMultiCall() {
Thread t = new Thread(new Runnable() {
@Override
public void run() {
while (true) {
long time = System.currentTimeMillis();
System.out.println("构造一个服务调用请求:");
WeatherFuture future = WeatherProxy.getWeatherInfo("广东深圳"
+ time, "2014-03-14");
WeatherResult info = future.get();
System.out.println("mockMultiCall结果:" + info);
System.out.println();
System.out.println();
}
}
});
t.start();
}
}
这样我们就按照active object模式的各个参与者及职责完成了java实现。