代码之家  ›  专栏  ›  技术社区  ›  perkss

Java:线程生产者消费者等待生成数据的最有效方法是什么

  •  6
  • perkss  · 技术社区  · 9 年前

    使用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.

    2 回复  |  直到 7 年前
        1
  •  5
  •   Pat B    9 年前

    等待数据生成的最有效方法是什么

    这个 BlockingQueue 具有阻塞功能,它将暂停线程,等待队列不为空或不为满。在您的情况下,您在消耗CPU的队列上旋转。这是不可取的。

    你应该使用 take .

    挂起将检索并删除此队列的头部,如果需要,等待元素变为可用。

    BlockingQueue#take

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

    然后你可以使用 put 其具有与 但仅当队列未满时。

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

    根据我们的意见进行更新:

    但在这种情况下,时间戳是按顺序创建的 补充。但未来时间戳可能会更少。E、 g.头部节点为2 分钟,第二个节点是1分钟,因此第二个需要 先处理

    然后我的跟进:

    所以您需要基于LocalDate的时间戳进行优先级排队?

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

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

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

    在这种情况下,您将处理 本地日期 按照他们的自然顺序,而不是排队的顺序。

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

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

        2
  •  0
  •   Jose Martinez    9 年前

    首先您需要使用 take 方法当队列为空时,此方法将阻塞。这将替换您的支票,以查看队列是否为空。

    第二,为什么需要时间戳?如果时间戳是为了确保您按照请求被放入队列的顺序处理请求,那么您不需要它,因为队列是FIFO的,是为并发多线程环境而设计的。如果时间戳来自系统外部,一些外部时间戳,其中请求可能会出现问题,但随后需要按顺序处理,则此BlockQueue不会删除它。你可能需要一个 PriorityBlockingQueue 其中您将按时间戳对请求进行优先级排序。所以要么去掉时间戳,要么使用 优先级阻塞队列 .