java多线程设计模式笔记之Active Object

来源:互联网 发布:mac看视频缺少插件 编辑:程序博客网 时间:2024/06/06 04:31

今天要说的模式是前几个模式的综合体,也是这个系列的最后的一个模式,叫做接受异步消息的主动对象。与之相关的模式有java多线程设计模式之Future Pattern、 java多线程设计模式之消费者生产者模式、 java多线程设计模式之Guarded Suspension等,如果不了解这几个模式,最好先看下这几个模式。

何为主动对象,一般来说是指自己拥有独立的线程的对象,在这里不只是拥有独立线程,还可从外部接受异步消息,并能配合需要返回处理结果。代码是最好的老师,上代码:

首先是主动对象接口,为什么要接口呢,因为这里使用了代理模式:

public interface ActiveObject {    Result makeString(int count,char fillChar);    void displayString(String string);}
我们的主动对象: 
public class Servant implements ActiveObject{    @Override    public Result makeString(int count, char fillChar) {        char[] buffer = new char[count];        for (int i = 0; i < count; i++) {            buffer[i] = fillChar;            try {                Thread.sleep(100);            } catch (InterruptedException e) {                e.printStackTrace();            }        }        return new RealResult(new String(buffer));    }    @Override    public void displayString(String string) {        System.out.println("display string"+string);        try {            Thread.sleep(10);        } catch (InterruptedException e) {            e.printStackTrace();        }    }}
两个简单的方法,一个生成一个字符串传入RealResult类对象,一个现实一个字符串。RealResult相信看过FuturePattern就知道是什么意思。至于RealResult代码是什么,稍后会说。

主动对象的代理类,持有主动对象的引用,被客户端实际调用的类,也是主动对象和调度线程SchedulerThread的中介者。至于调度线程,也是稍后再谈。

public class Proxy implements   ActiveObject {    private final SchedulerThread schedulerThread;    private final Servant servant;    public Proxy(SchedulerThread schedulerThread, Servant servant) {        this.schedulerThread = schedulerThread;        this.servant = servant;    }    public Result makeString(int count,char fillchar){        FutureResult futureResult = new FutureResult();        schedulerThread.invoke(new MakeStringRequest(servant,futureResult,count,fillchar));        return futureResult;    }    public void displayString(String string){        schedulerThread.invoke(new DisplayStringRequest(servant,string));    }}

这里Proxy持有Servant和SchedulerThread的引用,在makeString的时候将一个FutureResult(作用和Future Pattenr中的FutureResult一样)的对象那传入一个MakeStringRequest的对象,然后SchedulerThread的invoke方法接受MakeStringRequest的对象作为参数。

主动对象的工厂类:

public class ActiveObjectFactory {    public static ActiveObject createActiveObject(){        Servant servant = new Servant();        ActivationQueue queue = new ActivationQueue();        SchedulerThread schedulerThread = new SchedulerThread(queue);        Proxy proxy = new Proxy(schedulerThread,servant);        schedulerThread.start();        return proxy;    }}

该类直接和客户端打交道,客户端使用主动对象都是从该类获取,并且返回的是ActiveObject接口,实现了解耦。


调度线程:

public class SchedulerThread extends Thread{    private  ActivationQueue activationQueue;    public SchedulerThread(ActivationQueue activationQueue) {        this.activationQueue = activationQueue;    }    public void invoke(MethodRequest methodRequest){        activationQueue.putRequest(methodRequest);    }    @Override    public void run() {        while (true){            MethodRequest methodRequest = activationQueue.takeRequest();            methodRequest.execute();        }    }}

如果看过生产着消费者模式就会觉得很简单,持有一个ActiveationQueue对象(看名字就知道是请求队列),然后invoke方法就是将一个MethodeRequest放入队列,而本身开启的线程则是循环从队列中取出请求执行请求的execute方法。

结合上面的Proxy就能看出,Proxy主要就是将MakeStringRequest和DiaplayStringRequest放入ActiveationQueue对象。


请求队列ActiveationQueue:

public class ActivationQueue {    private static final int MAX_REQUEST = 100;    private MethodRequest[] methodRequests;    //下一个要放的位置    private int tail;    //下一个要取的位置    private int head;    //蛋糕数量    private int count;    public ActivationQueue() {        this.methodRequests = methodRequests = new MethodRequest[MAX_REQUEST];        tail = 0;        head = 0;        count = 0;    }    public synchronized void putRequest(MethodRequest methodRequest){        while (count >= methodRequests.length){            try {                wait();            } catch (InterruptedException e) {                e.printStackTrace();            }        }        methodRequests[tail] = methodRequest;        tail = (tail+1)%methodRequests.length;        count++;        notifyAll();    }    public synchronized MethodRequest takeRequest() {        while (count <= 0){            try {                wait();            } catch (InterruptedException e) {                e.printStackTrace();            }        }        MethodRequest methodRequest = methodRequests[head];        head = (head+1)%methodRequests.length;        count--;        notifyAll();        return methodRequest;    }}

一个很普通的阻塞队列,对生产着消费者模式不熟悉的可以看java多线程设计模式之消费者生产者模式,这是一个很重要的模式。

接下来谈下请求积基类MethodRequest,也就是异步消息。在上面的SchedulerThread的invoke方法,是将一个方法调用转化为一个异步消息,让另一个线程去执行,这也是一种很重要的设计思想。

public abstract class MethodRequest {    protected final Servant servant;    protected final FutureResult futureResult;    public MethodRequest(Servant servant, FutureResult futureResult) {        this.servant = servant;        this.futureResult = futureResult;    }    public abstract void execute();}

具体的请求:

public class MakeStringRequest extends MethodRequest{    private final int count;    private final char fillChar;    public MakeStringRequest(Servant servant, FutureResult futureResult, int count, char fillChar) {        super(servant, futureResult);        this.count = count;        this.fillChar = fillChar;    }    @Override    public void execute() {        Result result = servant.makeString(count,fillChar);        futureResult.setResult(result);    }}

public class DisplayStringRequest extends MethodRequest{    private final String string;    public DisplayStringRequest(Servant servant, String string) {        super(servant, null);        this.string = string;    }    @Override    public void execute() {        servant.displayString(string);    }}

如果了解 java多线程设计模式之Future Pattern,那很容易理解,在Proxy的makeString方法中返回的是一个Result对象,实际为FutureResult,在这里可以看到FutureResult必须等到Servant的makeString方法(耗时操作)返回RealResult之后才可以持有RealResult对象的引用。


再看下Result:

public abstract class Result {    public abstract Object getResultValue();}

ublic class FutureResult extends Result{    private Result result;    private boolean ready;    public synchronized void setResult(Result result){        this.result = result;        ready = true;        notifyAll();    }    public synchronized Object getResultValue(){        while (!ready){            try {                wait();            } catch (InterruptedException e) {                e.printStackTrace();            }        }        return result.getResultValue();    }}

public class RealResult extends Result{    private final Object resultValue;    public RealResult(Object resultValue) {        this.resultValue = resultValue;    }    public Object getResultValue() {        return resultValue;    }}


最后是客户端线程:

public class MakerClientThread extends Thread{    private final ActiveObject activeObject;    private final char fillchar;    public MakerClientThread(String name, ActiveObject activeObject) {        super(name);        this.activeObject = activeObject;        this.fillchar = name.charAt(0);    }    @Override    public void run() {        try {            for (int i = 0; true; i++) {                 Result result = activeObject.makeString(i,fillchar);                Thread.sleep(10);                String value = (String) result.getResultValue();                System.out.println(Thread.currentThread().getName() + " getValue:" + value);             }        } catch (InterruptedException e) {            e.printStackTrace();        }    }}

制作字符串线程通过调用主动对象的makeString得到Result(FutureResult),等待一段时间后从Result中取结果。


public class DisplayClientThread extends Thread {        private final  ActiveObject activeObject;    public DisplayClientThread(String name, ActiveObject activeObject) {        super(name);        this.activeObject = activeObject;    }    @Override    public void run() {        try {        for (int i = 0; true; i++) {                String string  =Thread.currentThread().getName()+ " " + i;                activeObject.displayString(string);                Thread.sleep(200);            }        } catch (InterruptedException e) {            e.printStackTrace();        }    }}

循环调用主动对象的displayString方法。

Main:



public class Main1 {    public static void main(String args[]){        ActiveObject activeObject = ActiveObjectFactory.createActiveObject();        new MakerClientThread("A",activeObject).start();        new MakerClientThread("B",activeObject).start();        new DisplayClientThread("C",activeObject).start();    }}

运行结果
display stringC 0
A getValue:
B getValue:
A getValue:A
B getValue:B
display stringC 1
A getValue:AA
B getValue:BB
display stringC 2
display stringC 3
A getValue:AAA
display stringC 4
B getValue:BBB
display stringC 5
A getValue:AAAA
display stringC 6

 ..........


这个综合的模式中除了运用了多个多线程的模式外,也运用了面向对象解耦的设计思想,客户端线程和主动对象、调度线程和主动对象它们之间并没有直接的耦合。真正处理数据的只有Servant,但因为有耗时操作,所以放在新的线程SchedulerThread中,这也使得运行Servant的是单线程,所以即使发出请求的客户端线程有多个,也保证了Servant的线程安全。

1 0