使用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())
来自之前的question.
答案 0 :(得分:5)
等待数据生成的最有效方法是什么
BlockingQueue
具有阻塞功能,该功能将挂起等待队列不为空或未满的线程。在你的情况下,你在消耗CPU的队列上旋转。这不是优选的。
您应该使用take
。
挂起检索并删除此队列的头部,必要时等待,直到元素可用为止。
这将是等待队列中元素的最有效方法,因为挂起线程不使用cpu。将新项目放入队列后,等待的线程将被唤醒。
然后您可以使用与put
具有相同等待语义的take
,但仅限于队列未满。
public void run(){
LocalTime timestamp = null;
while((timestamp = data.take()) != null){
...
}
}
根据我们的评论进行更新:
但在这种情况下,时间戳是按顺序创建的 添加。但是未来的时间戳可能会更少。例如。头节点是2 将来会有分钟,第二个节点是1分钟,所以第二个节点需要 首先处理
然后我跟进:
所以你需要根据LocalDate的时间戳来优先排队吗?
不确定您是使用JodaTime或Java 8中的LocalDate,让我们假设后者。
您可以使用具有相同阻止语义的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,只需创建自己的。
答案 1 :(得分:0)
您需要使用take
方法。当队列为空时,此方法将阻塞。这将替换您的检查以查看队列是否为空。
其次,为什么需要时间戳?如果时间戳是为了确保你处理请求,他命令将它们放入队列,那么你就不需要它,因为队列是FIFO并且是为并发多线程环境做的。如果时间戳来自系统外部,某些外部时间戳,请求可能无序,但需要按顺序处理,则此BlockQueue不会删除它。您可能需要PriorityBlockingQueue
,您可以按时间戳优先处理请求。因此,要么删除时间戳,要么使用PriorityBlockingQueue
。