Java 生产者/消费者工作队列

Java 生产者/消费者工作队列,java,concurrency,executorservice,producer-consumer,blockingqueue,Java,Concurrency,Executorservice,Producer Consumer,Blockingqueue,我正在努力寻找实现我的处理管道的最佳方法 我的制作人将工作提交给封锁队列。在使用者端,我轮询队列,将得到的内容包装到可运行任务中,然后将其提交给ExecutorService while (!isStopping()) { String work = workQueue.poll(1000L, TimeUnit.MILLISECONDS); if (work == null) { break; } executorService.execu

我正在努力寻找实现我的处理管道的最佳方法

我的制作人将工作提交给封锁队列。在使用者端,我轮询队列,将得到的内容包装到可运行任务中,然后将其提交给ExecutorService

while (!isStopping())
{
    String work = workQueue.poll(1000L, TimeUnit.MILLISECONDS);
    if (work == null)
    {
        break;
    }
    executorService.execute(new Worker(work));   // needs to block if no threads!
}
这并不理想;当然,ExecutorService有它自己的队列,所以真正发生的事情是,我总是完全排空我的工作队列并填充任务队列,随着任务的完成,任务队列会慢慢清空

我意识到我可以在生产者端对任务进行排队,但我真的不愿意这样做——我喜欢我的工作队列的间接/隔离是哑字符串;发生在他们身上的事与制片人无关。IMHO表示,强制生产者将可运行或可调用的文件排队会破坏抽象

但我确实希望共享工作队列表示当前的处理状态。如果消费者跟不上,我想阻止生产商

我很想使用遗嘱执行人,但我觉得我在与他们的设计抗争。我能喝一部分可乐吗,还是我必须把它吞下去?我在拒绝排队任务时是否有错误的想法?(我想我可以将ThreadPoolExecutor设置为使用单任务队列,并重写其execute方法以阻止而不是拒绝队列已满,但这感觉很糟糕。)

建议

我希望共享工作队列 表示当前处理 国家

尝试使用共享线程,并让工作线程池将工作项从队列中移除

我希望能够阻止 生产商,如果消费者不是 跟上

和都支持有界队列,这样它们在满时将阻塞。使用阻塞方法可确保在队列已满时阻塞生产者

这是一个艰难的开始。您可以调整工人数量和队列大小:

public class WorkerTest<T> {

    private final BlockingQueue<T> workQueue;
    private final ExecutorService service;

    public WorkerTest(int numWorkers, int workQueueSize) {
        workQueue = new LinkedBlockingQueue<T>(workQueueSize);
        service = Executors.newFixedThreadPool(numWorkers);

        for (int i=0; i < numWorkers; i++) {
            service.submit(new Worker<T>(workQueue));
        }
    }

    public void produce(T item) {
        try {
            workQueue.put(item);
        } catch (InterruptedException ex) {
            Thread.currentThread().interrupt();
        }
    }


    private static class Worker<T> implements Runnable {
        private final BlockingQueue<T> workQueue;

        public Worker(BlockingQueue<T> workQueue) {
            this.workQueue = workQueue;
        }

        @Override
        public void run() {
            while (!Thread.currentThread().isInterrupted()) {
                try {
                    T item = workQueue.take();
                    // Process item
                } catch (InterruptedException ex) {
                    Thread.currentThread().interrupt();
                    break;
                }
            }
        }
    }
}
公共类WorkerTest{
私有最终阻塞队列工作队列;
私人最终执行服务;
公共WorkerTest(int numWorkers,int workQueueSize){
workQueue=新的LinkedBlockingQueue(workQueueSize);
服务=Executors.newFixedThreadPool(numWorkers);
for(int i=0;i
您可以让消费者直接执行
Runnable::run
,而不是启动新线程。再加上一个最大大小的阻塞队列,我想你会得到你想要的。您的使用者将成为一个根据队列上的工作项内联执行任务的工作者。他们只会在处理商品时尽快将商品出列,这样当消费者停止消费时,你的生产商就可以放心了

查找可用的现有工作线程(如果存在),必要时创建一个,如果空闲则杀死它们

管理所有这些工人国家是不必要的,也是危险的。我将创建一个持续在后台运行的监控线程,它的唯一任务是填充队列并生成消费者。。。为什么不让工作线程守护进程完成后立即死亡?如果将它们全部附加到一个线程组,则可以动态地重新调整池的大小。。。例如:

  **for(int i=0; i<queue.size()&&ThreadGroup.activeCount()<UPPER_LIMIT;i++ { 
         spawnDaemonWorkers(queue.poll());
  }**

**(int i=0;iThanks;我以前的实现非常类似于此,尽管它只是使用了一个ThreadFactory-一旦你将它减少到一组固定的线程,所有线程都试图耗尽工作队列,那么再使用ExecutorService就没有什么意义了。我切换到ExecutorService是为了利用一个更可调的线程池,并且“查找可用的现有工作线程(如果存在),必要时创建一个,如果空闲则杀死它们。”Executors.newCachedThreadPool()的语义将做类似的事情。你也可以真正调整ThreadPoolExecutor本身的池策略。你想要的是什么?这就是想法…如果我愿意使用它的任务工作队列,它可以完全按照我喜欢的方式进行调整。我真正想要的是从executor中挖掘线程池智能并实现我自己的线程池客户端,但它并不是真正为此而设置的。这将只提供一个worker,我想对其进行调整,以最大限度地提高给定系统配置的处理。处理作业将持续几分之一秒到几十秒,并且是I/O绑定和CPU绑定工作的混合体。我假设多个使用者与一个或多个p关联制作人。如果你只有一个消费者,那么为什么不让制作人直接把作品交给执行人呢?正是我的想法。谢谢你写这篇文章。有趣的是,没有图书馆能做到这一点。