Java 等待多个QUEUE的使用者线程

Java 等待多个QUEUE的使用者线程,java,multithreading,producer-consumer,Java,Multithreading,Producer Consumer,我有多个任务队列和一个消费者线程 Consumer一旦任何队列有任务,线程应立即唤醒。所以我想知道什么是进行这种交流的最好方式 以下是一些可以解决这一问题的实现,并解释了为什么我想找到不同的东西: 实现这一点的一种方法是使用一些监视器对象和调用 .wait(timeout)从使用者线程对其执行操作,然后调用.notify() 从生产者线程。但是,这种方法使用wait/notify 是一种低级api,因此我希望尽可能避免使用它。而且这并不总是正确的,在某些情况下,当我们有任务要做时,我们可能会等

我有多个任务队列和一个
消费者
线程

Consumer
一旦任何队列有任务,线程应立即唤醒。所以我想知道什么是进行这种交流的最好方式

以下是一些可以解决这一问题的实现,并解释了为什么我想找到不同的东西:

  • 实现这一点的一种方法是使用一些监视器对象和调用
    .wait(timeout)
    从使用者线程对其执行操作,然后调用
    .notify()
    从生产者线程。但是,这种方法使用
    wait/notify
    是一种低级api,因此我希望尽可能避免使用它。而且这并不总是正确的,在某些情况下,当我们有任务要做时,我们可能会等待整个超时时间(睡眠理发师问题)
  • 类似于
    countdownlock
    reset
    方法的东西会很好, 但是我在
    java.util.concurrent
    中没有找到类似的内容。实现将相当简单,但是实现新自行车是我想要避免的事情,甚至比
    等待/notify
    还要多。另外,我相信它在等待整个超时时与
    wait/notify
    方法有相同的问题
  • 使生产者将创建的实体包装到一些
    任务中
    ,并使所有生产者写入同一队列,以便消费者可以侦听单个队列。我相信这种方法在大多数情况下都非常好,但在我的情况下,应用程序的这一部分具有较低的延迟要求,因此我必须避免创建新对象(例如,这些包装器),而且它还会增加队列尾部的争用(而不是一个使用者,所有使用者都会在那里写入)这对延迟也不是很好

那么有没有其他方法来实现它呢?(可能是使用其他一些并发原语)

在这种情况下,如果任务队列中的任何一个添加了项目,它也会将项目添加到标识队列中,那么如何使用任务通知队列呢

以下截图说明了这种方法:

import java.util.Queue;
import java.util.concurrent.ArrayBlockingQueue;

public class Main<T1, T2>  {


  Queue<T1> taskType1Queue = new ArrayBlockingQueue<T1>(10);
  Queue<T2> taskType2Queue= new ArrayBlockingQueue<T2>(10);
  ArrayBlockingQueue<Boolean> notificationQueue= new ArrayBlockingQueue<Boolean>(2);


  public void produceType1(T1 task) {
    new Thread(new Runnable() {
      @Override
      public void run() {
        taskType1Queue.add(task);
        notificationQueue.offer(true);; //does not block if full
      }
    });
  }

  public void produceType2(T2 task) {
    new Thread(new Runnable() {
      @Override
      public void run() {
        taskType2Queue.add(task);
        notificationQueue.offer(true); //does not block if full
      }
    });
  }


  public void consume() {

    try {
      notificationQueue.take();//wait till task1 o task2 has been published

      for(;!Thread.currentThread().isInterrupted();){
        T1 task1 = taskType1Queue.poll();//does not block if queue is empty
        if (task1 != null) {
          //do something
        }
        T2 task2 = taskType2Queue.poll();//does not block if queue is empty
        if (task2 != null) {
          //do something
        }
        if(task1 == null && task2 == null) {
          break;
        }
      }

    } catch (InterruptedException e) {
      System.out.println("Consumer thread done");
      return;
    }

  }

}
import java.util.Queue;
导入java.util.concurrent.ArrayBlockingQueue;
公共班机{
队列taskType1Queue=新的ArrayBlockingQueue(10);
队列taskType2Queue=新的ArrayBlockingQueue(10);
ArrayBlockingQueue notificationQueue=新的ArrayBlockingQueue(2);
公共无效生产类型1(T1任务){
新线程(newrunnable()){
@凌驾
公开募捐{
taskType1Queue.add(任务);
notificationQueue.offer(true);;//如果已满则不阻止
}
});
}
公共无效生产类型2(T2任务){
新线程(newrunnable()){
@凌驾
公开募捐{
taskType2Queue.add(任务);
notificationQueue.offer(true);//如果已满则不阻止
}
});
}
公共消费(){
试一试{
notificationQueue.take();//等待task1到task2已发布
对于(;!Thread.currentThread().isInterrupted();){
T1 task1=taskType1Queue.poll();//如果队列为空,则不会阻止
如果(task1!=null){
//做点什么
}
T2 task2=taskType2Queue.poll();//如果队列为空,则不会阻止
如果(task2!=null){
//做点什么
}
if(task1==null&&task2==null){
打破
}
}
}捕捉(中断异常e){
System.out.println(“消费线程完成”);
返回;
}
}
}

听起来像是阻塞队列可以工作。当产品有任务时,它会将其添加到BlockingQueue,消费者会开始工作,直到队列为空并再次等待。这些队列是阻塞的还是非阻塞的?您关于为什么不想使用单个队列的讨论被错误告知。例如,我会看看MPSC无锁队列。由于这本质上是一个性能问题,我不得不问您是否衡量了不同的解决方案。我真的不相信单队列多路复用增加了足够的延迟来抵消速度、简单性和可维护性方面的增益。对于低延迟,您根本不应该阻塞/等待/睡眠,正如所指出的那样。您需要的是一个非阻塞队列—例如,在紧循环中轮询队列—如果需要考虑功耗,请添加回退。如果您可以承受15毫秒的锁定暂停,那么这不是低延迟。@RuslanAkhundov通知队列如果已满,则不会阻塞,因此您的任务队列可以填满(最多10个任务),但通知只会在唤醒后两次。此外,您已经从使用1个队列(在发布内容时不会阻塞,并且在消费者准备就绪时可以随时使用)转变为使用三个队列,如果您需要另一个生产者,这三个队列很难扩展。@matt首先,我可以对任务队列使用无界队列,而不是有界队列。您认为很难添加其他使用者是对的,但我现在不可能对所有任务使用1个队列。我可以从产生相同类型任务的不同消费者那里写入队列,换句话说,每个任务类型我都有一个队列,我相信在我的情况下,它工作得非常好。@RuslanAkhundov因为你没有显示任务,所以没有办法说。这里提供的答案是错误的,可能是您让它工作了,所以这对您有好处。@matt通知队列阻塞,除非它有某些项(docs.oracle.com/javase/7/docs/api/java/util/concurrent/…take:检索并移除此队列的头,如果必要,等待元素可用),其想法是,如果任何队列中至少有一个项目,通知不应阻止,而是让单个队列在不被阻止的情况下进行检查(请参阅工作队列中非空项目的空检查),请详细说明是什么broken@AdrianWitas问题是你的报价,如果在其他任务完成之前提供多个任务,则通知队列将比任务队列短。因此,您将有无法获取com的任务