Java: Thread producer consumer 等待数据生产的最有效方式是什么

Java: Thread producer consumer what is the most efficient way to wait for data to be produced

当使用 BlockingQueue 消费产生的数据时,等待数据出现的最有效方法是什么?

场景:

步骤 1) 数据列表将是添加时间戳的数据存储。这些时间戳需要按照最接近当前时间的优先级排序。此列表可能为空。一个线程将把时间戳插入其中。 生产

步骤 2) 我想在另一个线程中使用这里的数据,该线程将从数据中获取时间戳并检查它们是否在当前时间之后。 消费者然后生产者

步骤 3) 如果它们在当前时间之后,则将它们发送到另一个线程以供使用和处理。此处处理时间戳数据后,从第 1 步数据存储中删除。 使用 然后编辑原始列表。

在下面的代码中,数据字段指的是步骤 1 中的数据存储。 结果是在当前时间之后发送的时间戳列表。第2步。 结果将在步骤 3 中使用。

private BlockingQueue<LocalTime> data;
private final LinkedBlockingQueue<Result> results = new LinkedBlockingQueue<Result>();

@Override
public void run() {
  while (!data.isEmpty()) {
    for (LocalTime dataTime : data) {
      if (new LocalTime().isAfter(dataTime)) {
        results.put(result);
      }
    }
  }
}

问题 等待数据添加到可能为空的数据列表中的最有效方法是什么?关注:

while (!data.isEmpty())

继之前

what is the most efficient way to wait for data to be produced

BlockingQueue 具有阻塞功能,可以暂停等待队列非空或非满的线程。在您的情况下,您正在消耗 CPU 的队列上旋转。这不是优选的。

你应该使用 take

Suspending retrieves and removes the head of this queue, waiting if necessary until an element becomes available.

BlockingQueue#take

这将是等待队列元素的最有效方式,因为挂起线程不消耗 cpu。一旦将新项目放入队列,等待线程将被唤醒。

然后您可以使用 put,它与 take 具有相同的等待语义,但前提是队列未满。

public void run(){
   LocalTime timestamp = null;
   while((timestamp = data.take()) != null){
      ...
   }
}

根据我们的评论更新:

But in this case the timestamps are created in a sequential order and added. But a timestamp may be less in the future. E.g. Head node is 2 mins in future, Second node is 1 min, so the second node wants processing first

然后我的跟进:

So you need priority queuing based on the timestamp of the LocalDate?

不确定您使用的是来自 JodaTime 的 LocalDate 还是 Java8,让我们假设后者。

您可以使用具有相同阻塞语义的 PriorityBlockingQueue。但是,BlockingQueue 的优先级方面将根据定义的任何顺序对元素进行排队。在您的情况下,使用 LocalDate 您可以让元素从最老到最年轻或从最年轻到最老排序。

BlockingQueue<LocalDate> data = new PriorityBlockingQueue<>(); 

OR INVERSE THE ORDER

BlockingQueue<LocalDate> data = new PriorityBlockingQueue<>(0, (a,b) -> b.compareTo(a));

在这种情况下,您将按 LocalDate 的自然顺序处理它们,而不是它们入队的顺序。

如果您使用的是 JodaTime 的 LocalDate,您可能需要实现自己的 Comparator 类似于我的第二个示例。

编辑: 刚刚意识到您将其标记为 java-7。因此,您将使用 JodaTime,如果 JodaTime LocalDate 未实现 Comparable,只需创建您自己的。

首先你需要使用take方法。当队列为空时,此方法将阻塞。这将取代您检查队列是否为空。

其次,为什么需要时间戳?如果时间戳是为了确保您按照将请求放入队列的顺序处理请求,那么您不需要它,因为队列是 FIFO 并且是为并发多线程环境创建的。如果时间戳来自系统外部,一些外部时间戳,请求可能会乱序但需要按顺序处理,那么这个 BlockQueue 将不会削减它。您可能需要一个 PriorityBlockingQueue ,您可以在其中按时间戳对请求进行优先级排序。所以要么去掉时间戳,要么使用 PriorityBlockingQueue.