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

今天要说的模式是前几个模式的综合体,也是这个系列的最后的一个模式,叫做接受异步消息的主动对象。与之相关的模式有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的线程安全。

发布了69 篇原创文章 · 获赞 76 · 访问量 8万+

猜你喜欢

转载自blog.csdn.net/sinat_23092639/article/details/53452970