当前位置: 首页 > 知识库问答 >
问题:

等待空阻塞队列的首选方法

柯捷
2023-03-14

我有一个多线程应用程序,其中一个线程将项目放入< code>BlockingQueue中,多个线程从中取出项目进行处理。问题是关于从队列中获取项目,目前它是这样实现的:

class PriorityQueueWorker<T> implements Runnable {
  private final PriorityBlockingQueue<T> requestQueue;
  private final AtomicBoolean continueExecution;

  @Override
  public void run() {
    do {
      T request = null;
      try {
        request = requestQueue.take();
      } catch (InterruptedException e) {
        Thread.currentThread().interrupt();
        continueExecution.set(false);
      }

      if (request == null) {
        continue;
      }

      //... here we do the work

    } while (continueExecution.get());

}

根据<code>BlockingQueue的JavaDoc。take()它检索并删除队列的头部,如果需要,等待元素可用,对于<code>PriorityBlockingQueue直到队列中出现一个项目:

public E take() throws InterruptedException {
  final ReentrantLock lock = this.lock;
  lock.lockInterruptibly();
  E result;
  try {
    while ((result = dequeue()) == null)
      notEmpty.await();
  } finally {
    lock.unlock();
  }
  return result;
}

实现我们的逻辑的另一种方法是使用优先级阻止Queue.poll(),它在空队列的情况下返回空值

public E poll() {
  final ReentrantLock lock = this.lock;
  lock.lock();
  try {
      return dequeue();
  } finally {
      lock.unlock();
  }
}

据我所知,这些方法的不同之处在于,使用fet()线程在等待的空队列中被阻塞,而使用轮询()它们继续围绕PriorityQueueWorker.run()中的无限循环旋转。

对我来说,队列长时间为空的用例非常普遍,所以我的问题是哪种方法从性能角度来看更好:保持线程阻塞(采取方法)或保持它们旋转(轮询方法)?

共有1个答案

佟阳焱
2023-03-14

从性能角度来看,哪种方法更好...?

“性能”对您意味着什么?

轮询空队列的工作线程将尝试使用 100% 的 CPU 内核。这将限制该内核代表任何其他线程工作的可用性。它还消耗电力,并产生热量。但是,如果应用程序中的线程数与 CPU 内核数仔细匹配,则可能会使工作线程更快地响应新工作项:当工作项到达时,很有可能某些工作线程已经处于核心中并正在运行并能够立即处理它。

在很多(大多数?)应用程序,OTOH,在应用程序中会有其他线程和在机器上运行的其他进程都希望共享CPU核心。在这种情况下,使用< code>take()可以在您的员工无事可做时释放CPU内核来做其他事情。那也是一种“表演”此外,使用< code>take()意味着您的应用将消耗更少的电力(如果您的应用可以在电池供电的设备上运行,这是一件大事),并且它将产生更少的热量(如果您的应用在数据中心或炎热的环境中运行,这可能是一个问题)。)而< code>take()的缺点是,当一个新的工作项到达时,操作系统需要一些时间来“唤醒”一个等待的工作线程,以便它可以开始处理它。

IMO:您应该从< code>take()开始,只有在您确定(即,如果您已经测量了性能)您有问题,并且您确定(再次测量)轮询可以修复问题时,才尝试轮询。此外,除非您能够保证执行轮询的线程数量少于可用内核的数量,否则不要尝试轮询。

 类似资料:
  • 问题内容: 我有两个分开的阻塞队列。客户端通常使用第二个阻塞队列中的第一个来检索要处理的元素。 在某些情况下,客户端对两个阻塞队列中的元素感兴趣,无论哪个队列首先提供数据。 客户端如何并行等待两个队列? 问题答案: 您可以尝试在某种循环中使用该方法,以仅在指定时间量内等待一个队列,然后再轮询另一个队列。 除此之外,我会说在另一个线程上为每个队列运行阻塞操作并为您的主应用程序提供回调接口是另一个稍微

  • 等待队列 到目前为止,我们的实验中,用户进程或内核线程还没有睡眠的支持机制。在课程中提到用户进程或内核线程可以转入等待状态以等待某个特定事件(比如睡眠,等待子进程结束,等待信号量等),当该事件发生时这些进程能够被再次唤醒。内核实现这一功能的一个底层支撑机制就是等待队列wait_queue,等待队列和每一个事件(睡眠结束、时钟到达、任务完成、资源可用等)联系起来。需要等待事件的进程在转入休眠状态后插

  • 等待队列接口 结构体 struct   rt_wqueue   等待队列控制块 更多...   struct   rt_wqueue_node   等待队列节点 更多...   宏定义 #define  RT_WQ_FLAG_CLEAN   0x00   等待队列清除   #define  RT_WQ_FLAG_WAKEUP   0x01   等待队列唤醒   #define  DEFINE_WA

  • 问题内容: 我在一个非常简单的生产者-消费者场景中使用 java.util.concurrent.BlockingQueue 。例如,此伪代码描述了使用者部分: 到目前为止,一切都很好。在阻塞队列的javadoc中,我读到: BlockingQueue本质上不支持任何类型的“关闭”或“关闭”操作,以指示将不再添加任何项目。这些功能的需求和使用往往取决于实现。例如,一种常见的策略是让生产者插入特殊的

  • blpop key1...keyN timeout 从左到右扫描返回对第一个非空list进行lpop操作并返回,比如blpop list1 list2 list3 0 ,如果list不存在list2,list3都是非空则对list2做lpop并返回从list2中删除的元素。如果所有的list都是空或不存在,则会阻塞timeout秒,timeout为0表示一直阻塞。当阻塞时,如果有client对ke

  • 我编写了一个简单的类,我计划将其扩展为客户端套接字编程应用程序的一部分。类涉及一个BlockingQueue(我从这里复制了代码:相当于Java的BlockingQueue的C++)。当我创建了下面的包装类的一个实例后,我打算让它生成一个单独的线程,该线程只需执行BlockingQueue上阻塞的printer()函数,直到有一个或多个字符串可用,然后它只需将字符串打印到控制台窗口。在我的预期应用