一、活动对象定义:
活动对象工作在对象级别而不像其他设计模式工作在对象继承层级关系中。它将方法的调用和其实际的执行解耦,方法的执行位于对象本身的控制线程中,因而也不会阻塞调用者。总的说来,活动对象模式有6个元素:
1.代理。以公共方法的方式向客户对象提供访问接口。
2.接口。定义了活动对象上的方法请求。
3.队列。保存来自客户的挂起的请求。
4.调度器。决定从挂起的队列中选取哪个请求来执行。
5.实现。活动对象方法的实现。
6.回调/变量。客户对象用它来获取请求执行的结果,活动方法的执行结果通常被封装到成为future的对象中。该future对象中包含了一个类似于占位符的东西。一旦活动对象完成了方法执行就会将结果放到future的占位符上。但在方法完成之前尝试获取占位符上的内容将会阻塞线程。
二、活动对象的特征:
基于消息机制:对活动对象的请求和可能的参数都被转化为消息,这些消息被转发给活动对象实际实现并排队等待处理。处理结果以future对象返还给提出请求的对象。
异步调用:对活动对象的请求被异步执行,实际由活动对象的工作线程处理请求,故不会阻塞调用者。仅当请求未完成执行时,调用者试图获取处理结果时会被阻塞。
线程安全:活动对象天生是线程安全的。因为他顺序地从请求队列摘取消息进行处理,并且始终在一个单独的线程中执行,由于不存在资源竞争,所以也不用担心同步、死锁等问题。同步仍旧会发生,但它通过将方法调用排队,使得任何时刻都只能发生一个调用,从而将同步控制在消息的级别上发生。
三、活动对象的应用场景:
适合于实时跟踪具有按某一特定顺序执行而又互不影响的多线程任务其执行状况的情景
4、活动对象的实例:
- import java.util.*;
- import java.util.concurrent.*;
- public class ActiveObjectsDemo {
- //创建ActiveObjectDemo对象的工作线程,Executors.newSingleThreadExecutor()创建的是单个线程
- //所有在ex中执行的方法都在这个线程中串行地逐个执行
- private ExecutorService ex=
- Executors.newSingleThreadExecutor();
- private Random rand=new Random(47);
- private void pause(int factor){
- try{
- TimeUnit.MICROSECONDS.sleep(100+rand.nextInt(factor));
- }catch(InterruptedException e){
- System.out.println("sleep() interrupted");
- }
- }
- public Future<Integer> calculateInt(final int x ,final int y){
- /*
- * ExecutorService的submit方法启动的线程会返回一个Future对象
- * 当方法执行完毕会将结果保存到该Future对象中。
- */
- return ex.submit(new Callable<Integer>() {
- public Integer call(){
- System.out.println("starting "+x+"+"+y);
- pause(2000);
- return x+y;
- }
- });
- }
- public Future<Float> calculateFloat(final float x ,final float y){
- /*
- * ExecutorService的submit方法启动的线程会返回一个Future对象
- * 当方法执行完毕会将结果保存到该Future对象中。
- */
- return ex.submit(new Callable<Float>() {
- public Float call(){
- System.out.println("starting "+x+"+"+y);
- pause(2000);
- return x+y;
- }
- });
- }
- public void shutdown() {
- ex.shutdown();
- }
- public static void main(String[] args) {
- ActiveObjectsDemo demo=new ActiveObjectsDemo();
- //使用CopyOnWriteArrayList可以防止并发修改异常(ConcurrentModificationException)
- List<Future<?>> results=new CopyOnWriteArrayList<Future<?>>();
- /*
- * 所有对calculateFloat和calculateInt读调用都是立即返回
- * 并且就算是“同时”调用这些方法,它们也会排队串行执行,避免了显示地同步需求
- */
- for(float f=0.0f;f<1.0f;f+=0.2f)
- results.add(demo.calculateFloat(f, f));
- for(int i=0;i<5;i++)
- results.add(demo.calculateInt(i, i));
- System.out.println("All asynch calls made");
- while(results.size()>0){
- for(Future<?> f: results){
- try{
- //阻塞并获取调用结果
- System.out.println(f.get());
- }catch(Exception exception){
- throw new RuntimeException(exception);
- }
- results.remove(f);
- }
- }
- demo.shutdown();
- }
- }