【问题标题】:ThreadPoolExecutor - ArrayBlockingQueue ... to wait before it removes an element form the QueueThreadPoolExecutor - ArrayBlockingQueue ...在从队列中删除元素之前等待
【发布时间】:2011-04-21 01:45:42
【问题描述】:

我正在尝试调整执行以下操作的线程:

只有 1 个线程的线程池 [CorePoolSize =0, maxPoolSize = 1]

使用的队列是ArrayBlockingQueue

Quesize = 20

背景:
线程尝试读取请求并对其执行操作。

但是,最终请求增加得如此之多,以至于线程总是很忙并消耗 1 个 CPU,这使其成为资源占用。

我想做的是,每隔一段时间对请求进行采样并处理它们。可以安全地忽略其他请求。

我要做的就是在“操作”函数中设置一个睡眠,这样对于每个任务,线程都会睡眠一段时间并释放 CPU。

问题:
但是,我想知道是否有一种方法可以使用一个队列,该队列基本上本身会在读取下一个元素之前休眠一段时间。这将是理想的,因为在执行过程中休眠任务并保持执行不完整对我来说听起来并不是最好的。

如果您对任务还有其他建议,请告诉我

谢谢。

编辑: 我添加了一个后续问题here 将 maxpool 大小更正为 1 [匆忙编写] .. 感谢 tim 指出。

【问题讨论】:

  • 这并不是真正的“资源消耗”,还有很多工作要做。你真的想人为地减慢请求吗?为什么请求(客户端?)的发送速度比处理速度快?这是不可持续的。
  • 好点。如果客户端发出大量请求,但由于队列已满而被拒绝,则它们正在浪费本可以在客户端和执行程序之间更好地平衡的 CPU。队列是一个缓冲区,可以随着时间的推移“平滑”负载;拒绝应该是罕见的,而不是例行公事。
  • 客户端并不是真正意义上的请求者的专用客户端。请求者有一个专门的客户端,它会根据请求的数量进行扩展。我正在工作的客户端就像一个额外的日志记录,监控操作类型..因此采样仍然可以很好地了解请求..希望这是有道理的。
  • @p1,您的 maxPoolSize 不能为 0,这违反了 ThreadPoolExecutor 的构造函数中强制执行的不变量。如果您不确定,请使用您正在使用的正确值或您正在使用的确切构造方法更新您的问题。

标签: java multithreading thread-safety threadpool blockingqueue


【解决方案1】:

不,您不能让线程在池中时休眠。如果队列中有任务,就会执行。

在队列任务中暂停是强制线程处于空闲状态的唯一方法,尽管有队列任务。现在,“睡眠”不必与“工作”在同一个任务中——您可以在每个实际任务之后排队一个单独的休息任务,这可能会使实现更简洁。更重要的是,如果工作是返回结果的Callable,分成两个任务可以让你尽快得到结果。

作为一种改进,您可以将执行“节流”到指定速率,而不是在每个任务之间按固定间隔休眠。这将允许您避免在任务之间不必要地等待,同时避免在指定的时间间隔内执行过多的任务。您可以通过read another answer of mine 获得一种简单的方法来使用DelayQueue 实现此功能。

【讨论】:

    【解决方案2】:

    您可以继承 ThreadPool 并覆盖 beforeExecute 以休眠一段时间:

    @Overrides
    protected void beforeExecute(Thread t,
                             Runnable r){
        try{
           Thread.sleep( millis);  // will sleep the correct thread, see JavaDoc
        }
        catch (InterruptedException e){}
    
      }
    

    但请参阅 AngerClown 关于人为减慢队列速度的评论可能不是一个好主意。

    【讨论】:

    • 谢谢,Thilo .. 我认为 beforeExecute 可能会成功。如果工作正常,将进行更改并接受答案:)。保持线程打开以防有更多想法:)
    • +1 用于提及 beforeExecute 方法。人们有时对 ExecutorService 抽象如此着迷,以至于他们往往会忘记 ThreadPoolExecutor 实现也有一些简洁的产品。
    • 我尝试修改这种方法。有趣的是,@times beforeExecute() 被调用,然后立即执行任务而不休眠,然后在休眠时间过去后重新执行任务。我正在使用一个线程池,并且只有一个线程 [查看我的问题中的详细信息] .. 我错过了什么吗??
    【解决方案3】:

    这可能不适合您,但您可以尝试将执行程序的线程优先级设置为低。

    基本上,使用自定义ThreadFactory 创建ThreadPoolExecutor。让ThreadFactory.newThread() 方法返回优先级为Thread.MIN_PRIORITY 的线程。这将导致您使用的执行器服务仅在有可用核心运行时才被调度。

    含义:在严格使用时间片的系统上,只有在整个程序中没有其他具有更高优先级的线程要求调度时,才会给你一个时间片来执行。根据您的应用程序的实际繁忙程度,您可能会每隔一段时间被安排一次,或者您可能根本没有被安排。

    【讨论】:

    • 谢谢 .. 我曾考虑过这种方法,但我担心它可能会使我的线程饿死。此外,我的线程正在尝试对数据进行采样,因此我想要了解正在发生的事情的真实画面……这样做可能会使样本偏向仅 CPU 较低的时段……这违背了拥有线程的目的。此外,线程执行的单个任务非常小[但任务太多] ..所以我认为睡眠可能会更好。同意吗?
    • 是的,同意。我认为 Thilo 的解决方案是最好的,这就是我投赞成票的原因。
    【解决方案4】:

    线程消耗 100% CPU 的原因是因为它被分配了比它可以处理的更多的工作。在任务之间添加延迟并不能解决这个问题。只会让事情变得更糟。

    相反,您应该看看为什么您的任务会消耗如此多的 CPU,例如使用分析器并更改它们以减少 CPU 消耗,直到您发现线程可以跟上并且不再消耗 100% 的 CPU。

    【讨论】:

    • 这是显而易见的答案……就像 facebook 太忙了,延迟登录以防止人们使用网络。
    • @Javier,facebook 几乎无法控制请求进入的速率。有些人试图故意使服务器超载以查看会发生什么。您的代码可能会假设工作负载“更友好”
    猜你喜欢
    • 1970-01-01
    • 2017-09-16
    • 1970-01-01
    • 2021-08-18
    • 1970-01-01
    • 1970-01-01
    • 2012-06-01
    • 2012-09-01
    • 1970-01-01
    相关资源
    最近更新 更多