【问题标题】:java executor with pre-emptable thread queue具有可抢占线程队列的 java 执行器
【发布时间】:2010-07-22 09:33:38
【问题描述】:

我正在寻找一个 java 线程池,它不会同时运行比系统中的内核更多的线程。该服务通常由使用 BlockingQueue 的 ThreadPoolExecutor 提供。

但是,如果计划执行一个新线程,我希望新线程抢占已经运行的线程之一,并将被抢占的线程(处于挂起状态)添加到任务队列中,所以新线程一结束就可以恢复。

有什么建议吗?

【问题讨论】:

  • 我认为 Java 线程不应该那样使用,因为不可能暂时停止然后继续线程,除非您自己实现这样的方法。但是没有通用的方法来抢占一个可运行的,暂停执行并让另一个线程继续。事实上,运行的线程数永远不会超过系统中的内核数。这是一个简单的物理定律。如果您运行的线程多于系统中的内核数,java 会自动在运行的线程中调度可用的 CPU(使用抢占)。
  • 感谢您的回复。我知道线程暂停在 java 中已被弃用,但是这里已经描述了其他方法:download.oracle.com/docs/cd/E17476_01/javase/1.4.2/docs/guide/…。我已经实现了一个类似的方法来暂停我的线程。我的目标是尽快完成“新”任务。

标签: java multithreading scheduling


【解决方案1】:

我会创建一个 ThreadPoolExecutor 的子类。

当您设置 ThreadPoolExecutor 时,您希望将 corePoolSizemaximumPoolSize 设置为 Runtime.getRuntime().availableProcessors()(查看 Executors.newFixedThreadPool() 以了解其工作原理)。

接下来,您要确保您的 Queue 也实现了 DequeLinkedBlockingDeque 是一个示例,但您应该货比三家,看看哪一个最适合您。 Deque 可以让您获得类似 LIFO 的堆栈行为,这正是您想要的。

由于所有内容(submit()invokeAll())都通过execute() 漏斗,您将需要覆盖此方法。基本上做你上面描述的:

检查是否所有线程都在运行。如果不是简单地在可用线程上启动新的可运行文件。如果所有线程都已在运行,那么您需要找到运行最旧的可运行对象的线程,停止可运行对象,将可运行对象重新排入某个位置(可能在开始时?),然后启动新的可运行对象。

【讨论】:

    【解决方案2】:

    ThreadPoolExecutor 的想法是避免所有与创建和销毁线程相关的昂贵操作。如果您绝对坚持抢占正在运行的任务,那么您将无法从默认 API 中获得。

    如果您愿意让正在运行的任务完成,而只抢占尚未开始执行的任务,那么您可以使用 BlockingQueue 实现,其工作方式类似于堆栈 (LIFO)。

    您还可以通过使用具有不同线程优先级的不同执行器来让任务“抢占”其他任务。本质上,如果操作系统支持时间片,那么更高优先级的执行者会获得时间片。

    否则,您需要一个管理执行的自定义实现。您可以使用 SynchronousQueue 并让 P 个工作线程等待它。如果客户端调用 execute 并且 SynchronousQueue.offer 失败,那么您将必须创建一个特殊的工作线程,该线程会抓取其他线程之一并在执行前将它们标记为暂停,并在执行后再次将它们标记为恢复。

    【讨论】:

      猜你喜欢
      • 2021-05-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-09-07
      • 1970-01-01
      • 1970-01-01
      • 2010-11-13
      • 1970-01-01
      相关资源
      最近更新 更多