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.
这将是等待队列元素的最有效方式,因为挂起线程不消耗 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
.
当使用 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.
这将是等待队列元素的最有效方式,因为挂起线程不消耗 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
.