java active object 并发模式

来源:互联网 发布:手机淘宝联盟推广教程 编辑:程序博客网 时间:2024/06/12 00:15

Active Object 是并发编程实践中典型的异步编程模式,Active Object 模式的核心是通过解耦合方法的调用与执行来提高程序的并发度。
Active Object模式中一个核心概念就是并发对象,它不同于一般的对象,该对象方法的调用与方法的执行不在同一个线程內,也即:该对象方法被调用者线程共享。既然并发对象那么重要,那如何设计一个并发对象呢,需要考虑下面的几个重要因素:
1)并发对象的任何一次的方法执行,不允许无限地或者长时间阻止其它方法的调用执行,从而影响应用的 QoS。
2)由于并发对象被调用者线程所共享,其内部状态必须保证是线程安全的,必须受限于某些线程同步约束,并且这些约束对调用者来说是透明的,不可见的。从调用者的角度来看,并发对象与普通对象没有多大区别。
3)并发对象的设计实现,应该能够透明地利用底层平台所提供的并发机制。这样做的好处是,当并发对象运行在诸如多核处理器这类底层硬件平台上时,我们的应用能够充分挖掘底层平台带来的并发优势,以获得足够好的应用性能。

从设计的角度来看,在 Active Object 模式中,主要有以下几种类型的参与者:
1)代理 (Proxy) :代理是 Active Object 所定义的对于调用者的公共接口。运行时,代理运行在调用者线程的上下文中,负责把调用者的方法调用转换成相应的方法请求 (Method Request),并将其插入相应的 Activation List,最后返回给调用者 Future 对象。
2)方法请求:方法请求定义了方法执行所需要的上下文信息,诸如调用参数等。
3)Activation List:负责存储所有由代理创建的,等待执行的方法请求。从运行时来看,Activation List 会被包括调用者线程及其 Active Object 线程并发存取访问,所以,Activation List 实现应当是线程安全的。
4)调度者 (Scheduler):调度者运行在 Active Object 线程中,调度者来决定下一个执行的方法请求,而调度策略可以基于很多种标准,比如根据方法请求被插入的顺序 FIFO 或者 LIFO,比如根据方法请求的优先级等等。
5)Servant: Servant 定义了 Active Object 的行为和状态,它是 Proxy 所定义的接口的事实实现。
6)Future: 调用者调用 Proxy 所定义的方法,获得 Future 对象。调用者可以从该 Future 对象获得方法执行的最终结果。在真实的实现里,Future 对象会保留一个私有的空间,用来存放 Servant 方法执行的结果。

基于JDK5提供的concurrent并发包来实现一个ActiveObject(当然不使用并发包也是可以实现的,那么这里面考虑的问题就多了,比如请求方法的保存,请求方法的调度执行等)。

package com.tuobana.concurrent.ActiveObject;import java.util.concurrent.*;import java.util.concurrent.atomic.AtomicInteger;import java.util.concurrent.atomic.AtomicLong;/** * Created by lpn on 2016/3/8. */public class AysnRequestPersistence implements RequestPersistence {    private static final long ONE_MINUTE_IN_SECONDS = 60;    private final AtomicLong taskTimeConsumedPerInterval = new AtomicLong(0);    private final AtomicInteger requestSubmittedPerInterval = new AtomicInteger(0);    // 角色 Servant    private final DiskbasedRequestPersistence delegate = new DiskbasedRequestPersistence();    // 角色 scheduler和ActivationList合并    private final ThreadPoolExecutor scheduler;    // 角色Proxy    public static RequestPersistence getInstance() {        return InstanceHolder.INSTANCE;    }    // 对外方法    @Override    public void store(final Object request) {        // 角色方法请求        Callable<Boolean> methodRequest = new Callable<Boolean>() {            @Override            public Boolean call() throws Exception {                long start = System.currentTimeMillis();                try {                    // 调用Servant的实际方法,此处也可以省略Servant,直接实现                    delegate.store(request);                } finally {                    taskTimeConsumedPerInterval.addAndGet(System.currentTimeMillis() - start);                }                return Boolean.TRUE;            }        };        scheduler.submit(methodRequest);        requestSubmittedPerInterval.incrementAndGet();    }    private static class InstanceHolder {        final static RequestPersistence INSTANCE = new AysnRequestPersistence();    }    private AysnRequestPersistence() {        scheduler = new ThreadPoolExecutor(1, 30, ONE_MINUTE_IN_SECONDS, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(200), new ThreadFactory() {            @Override            public Thread newThread(Runnable r) {                Thread t = new Thread(r, "AysnRequestPersistence");                return t;            }        });        scheduler.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());        ScheduledExecutorService monitor = Executors.newScheduledThreadPool(1);        monitor.scheduleAtFixedRate(new Runnable() {            @Override            public void run() {                System.out.println("task count:" + requestSubmittedPerInterval                        + ",Queue size:" + scheduler.getQueue().size()                        + ",taskTimeConsumedPerInterval:" + taskTimeConsumedPerInterval.get() + " ms");            }        }, 1, 30, TimeUnit.SECONDS);    }}

上面的代码不能正常运行,这是我摘抄了http://ifeve.com/java-active-object/中的部分代码,其余的代码可以参考上面的文章进行完善,这里主要是想体验一下利用JDK5提供的concurrent包如何方便快捷的实现并发对象。

Active Object 给我们的应用带来的好处:
1)极大提高了应用的并发性以及简化了线程同步带来的复杂性。并发性的提高得益于调用者线程与 Active Object 线程的并发执行。简化的线程同步复杂性主要表现在所有线程同步细节封装在调度者内 ( 也就是 Java 的 Executor 对象 ),Active Object 调用者并不需要关心。
2)在 Active Object 中,方法的执行顺序可以不同于方法的调用顺序。用 Java 的话说,也就是任务执行的顺序可以不同于任务提交的顺序。在一定情况下,这可以帮助优化我们应用的性能,提高应用的 QoS 及其 Responsiveness。在 Java Executor 框架下,你可以根据当前的计算资源,确定优化的执行策略 (Execution Policy),该执行策略的内容包括:任务将分配在多少线程上执行,以什么顺序执行,多少任务可以同时执行等等。

当然,Active Object 也有缺点:
1)额外的性能开销。这涉及到从调用者线程到 Active Object 线程的上下文切换,线程同步,额外的内存拷贝等。
2)难于调试。Active Object 引入了方法的异步执行,从调试者的角度看,调试这样的方法调用不像普通方法那样直截了当,并且这其中涉及到了线程的调度,同步等。

总之,active object是一种并发编程的模式,重要的是理解其思想,方法的调用和方法的执行分离,具体的实现方法其实有多种多样的变形,并不局限示例代码中的一种。

0 0
原创粉丝点击