与线程池的责任链

时间:2013-07-29 16:21:36

标签: java design-patterns architecture chain-of-responsibility

我有一系列责任,包括3个阶段。

Stages

我对这些阶段的实现看起来像这样。

public class InitialStage implements RecordHandler {

    private RecordHandler next;

    @Override
    public void setNext(RecordHandler handler) {
        if (this.next == null) {
            this.next = handler;
        } else {
            this.next.setNext(handler);
        }
    }

    @Override
    public void handleRequest(String record) {
        System.out.println("Processing @ Initial Stage.");
        if (next != null) {
            next.handleRequest(record);
        }
    }
}

流程经理

public class ProcessManager {
    private RecordProcessor processor = new RecordProcessor();

    public ProcessManager()
    {
        createPipeLine();
    }

    private void createPipeLine() {
        processor = new RecordProcessor();
        processor.addHandler(new InitialStage());
        processor.addHandler(new MiddleStage());
        processor.addHandler(new FinalStage());
    }

    public void processRecord(String record){
        processor.handleRequest(record);
    }
}

界面

public interface RecordHandler {
    public void setNext(RecordHandler handler);
    public void handleRequest(String record);
}

最后是RecordProcessor,

public class RecordProcessor {

    private RecordHandler successor;
    private RecordHandler first;

    public RecordProcessor(){
    }

    public void addHandler(RecordHandler recordHandler){
        if(this.first == null){
            this.first = recordHandler;
        }
        else{
            this.successor.setNext(recordHandler);  
        }
        this.successor = recordHandler;
    }

    public void handleRequest(String record){
        first.handleRequest(record);
    }
}

现在我发现我的中间阶段需要一些时间才能完成。所以现在我对使用线程池感兴趣,所以记录的处理方式如下所示。

这里假设有3个工作线程。

Suggested Chain

问题

如何正确修改现有的CoR以满足新要求?

2 个答案:

答案 0 :(得分:1)

为了社区的利益回答我自己的问题,因为我找到了一个可行的解决方案。

我为这个问题开发了略有不同的解决方案。我没有使用并行管道,而是使用了一个多线程的阶段。 (在这种情况下的中间阶段)。换句话说,中间阶段使用输入队列和输出队列,而不是传递单个记录。当输入队列填充了定义数量的记录时,线程会产生。

后续阶段可能空闲,直到队列已满,但仍然可以接受此实现。这可以在不需要排序时使用。如果需要遵循序列,则需要保留序列ID并在输出队列中执行排序。

中期

public class MiddleStage implements RecordHandler {

private RecordHandler next;
private ExecutorService executor = Executors.newFixedThreadPool(5);
private Queue<String> inbound = new LinkedList<String>();
Collection<Callable<String>> tasks = new ArrayList<Callable<String>>();

@Override
public void setNext(RecordHandler handler) {
    if (this.next == null) {
        this.next = handler;
    } else {
        this.next.setNext(handler);
    }
}

@Override
public void handleRequest(String record) {
    System.out.println("Adding new record to Queue : " + record);
    inbound.add(record);
    System.out.println("Queue Size : " + inbound.size());

    if (inbound.size() >= 10)
    {
        System.out.println("Processing the batch.");

        for (int i = 0; i < 10; i++){
            tasks.add(new MiddleWorker(inbound.poll()));
        }

        System.out.println("Processing @ Middle Stage. " + record);
        List <Future<String>> results = null;
        try {
            results = executor.invokeAll(tasks, 60, TimeUnit.SECONDS);
            tasks.clear();
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        for (Future<String> f : results) {
              try {
                String answer = f.get();
                System.out.println("Outbound : " + answer);
                if (next != null) {
                    next.handleRequest(answer);
                }

            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (ExecutionException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            }
        results.clear();
    }
}
}

MiddleWorker类

public class MiddleWorker implements Callable<String> {

private String output;

public MiddleWorker(String record)
{
    output = record + " : OK";
}

@Override
public String call() throws Exception {
    try
    {
        Thread.sleep(2 * 1000);
    }
    catch(final InterruptedException ex)
    {
        ex.printStackTrace();
    }

    return (output);
}
}

如果答案不清楚,请发表评论,我会修改答案。

答案 1 :(得分:0)

您可以创建一个额外的“阶段”,负责将工作负载传递给线程池。

public class PoolExecutingStage implements RecordHandler {

    private Executor threadPool;
    private RecordHandler next;

    public PoolExecutingStage(Executor tp) {
         this.threadPool = tp;      
    }

    @Override
    public void setNext(RecordHandler handler) {
           // similar to your example
    }

    @Override
    public void handleRequest(String record) {
        if (next != null) {
            threadPool.execute(new Runnable() {
                 public void run() {
                     next.handleRequest(record);
                 }
            });               
        }
    }
}

接下来,您需要通过在初始阶段和中间阶段之间添加对processor.addHandler(new PoolExecutingStage(configuredThreadPool));的调用,在您的管道中包含此新阶段。


还要注意处理在多个线程中运行它时可能需要的任何线程同步