使用ExecutorService在管道模式中多线程化一个阶段

时间:2013-01-11 15:54:28

标签: java multithreading design-patterns pipeline executorservice

我有一个多阶段管道。每个阶段都在一个单独的线程中运行,并使用有界的BlockingArrayQueues进行通信。我正在尝试多线程最慢的阶段以提高吞吐量。

问题:建议的实施方案是什么?是否有一个库可以使这个实现更简单&更容易阅读?

输入队列 - >阶段1(4个线程) - >有界队列 - >第二阶段

要求

  • 输入队列上的工作单位是独立的。

  • 工作单位是严格排序的 - 输出应与输入的顺序相同。

  • 必须限制第1阶段 - 如果输出超过特定大小,则必须停止。

  • 阶段1中的异常应导致输出队列中的“毒丸”并终止ExecutorService。排队的任务应该尽力丢弃。

**我的建议实施:**

我正在考虑使用具有有限线程数的ThreadPoolExecutor。

将使用每个工作单元上的CountDown锁存器强制执行严格的排序。如果前一个工作单元的锁存器为0并且队列中有空间,则线程只能推送结果。这也会处理限制,因为线程将阻塞,直到输出队列上有空间。

class WorkUnit {
   CountDownLatch previousLatch;
   CountDownLatch myLatch;
}

class MyRunnable extends Runnable {
   public void run() {
       //do work...
       previousLatch.await();
       ouputQueue.put( result );
       myLatch.countDown();
   }
}

异常处理是我有点难过的地方。我想要压倒一切 ThreadPoolExecutor.afterExecute()如果有异常将调用shutdownNow()。

class MyThreadPoolExecutor extends ThreadPoolExecutor {
      protected void afterExecute(Runnable r, Throwable t) {
           if(t != null) {
               //record exection, log, alert, etc
               ouput.put(POISON_PILL);
               shutdownNow();
           }
      }
}

1 个答案:

答案 0 :(得分:0)

使用ExecutorService需要完全异步设计,而不使用CountDownLatch.countDown()BlockingQueue.take()等阻止操作。当某个操作B必须等待某些事件时,该事件应该通过向Runnable提交ExecutorService来启动操作B.

在这种情况下,您应该创建自定义类而不是队列。这些类应该接受消息并在内部存储它们,或者根据一些规则提交实现Stage1或Stage2的任务(例如,限制正在运行的Stage1任务的数量)。

关于订购,请用序列号替换对上一个任务的引用。