【问题标题】:ThreadPoolExecutor threads having contention with other threads与其他线程争用的 ThreadPoolExecutor 线程
【发布时间】:2011-07-27 08:04:32
【问题描述】:

我正在对现有 Java 应用程序进行增强。该应用程序是一个消息处理器,每天处理数百万条消息。它基本上是使用 Core Java 编写的,线程和队列是使用 Collection 类实现的。

在此应用程序中,某些类型的消息在单个线程中运行。我的任务是使应用程序的这个特定部分成为多线程以更快地处理消息,因为我们有双处理器。

由于我们使用的是 Java 5,所以我采取了使用 ThreadPoolExcecutor 的方法。我为每个客户端创建了处理器线程,以便可以在其自己的线程中处理特定线程的消息。处理器线程正在实现 Callable 接口,因为这将允许我检查未来对象是否已完成前一个任务。

在初始化过程中,我将检查所有客户端并为每个客户端创建处理器线程,并使用它们的 id 作为唯一键将其存储在 map 中。为了跟踪之前提交的作业,我确实使用相同的 id 作为唯一键再次将未来对象保留在另一个地图中。

以下是我使用的一些 sn-p 代码:在主类中 -

ThreadPoolExecutor  threadPool = null;
int poolSize = 20;
int maxPoolSize = 50;
long keepAliveTime = 10;
final ArrayBlockingQueue<Runnable> queue = new ArrayBlockingQueue<Runnable>(1000);
threadPool = new ThreadPoolExecutor(poolSize, maxPoolSize,keepAliveTime, TimeUnit.SECONDS, queue);

   ....
   ....
 for (each client...) {
   id = getId()..
   future = futuremap.get(id);
   if(!future.isDone())
      continue;
   if(future == null || future.isDone()) {
      processor = processormap.get(id);
      if(processor == null) {
         processor = new Processor(.....);
         //add to the map
         processormap.put(id,processor);
      }
      //submit the processor
      future = threadPool.submit(processor );
      futuremap.put(id,future);
 }
} 

处理器线程

public class MyProcessor implements Callable<String> {
        .....
        .....
    public String call() {
        ....
        ....
    }
 }

问题

上述实现在我的测试环境中运行良好。但是,在生产环境中(Edit#1 - Ubuntu、Linux Slackware、Java - 1.6.0_18),我们观察到应用程序的其他线程不是通过这个管理的新的 ThreadpoolExecutor 受到影响。即,他们的任务被延迟了几个小时。是因为 ThreadPoolExecutors 创建的线程正在占用全部资源或其他任何资源,而没有给其他线程机会。

使用 ThreadPoolExceutor 创建的新线程正在执行独立的任务,并且不会与其他线程争用资源。即,没有竞争条件场景。

在日志中,对于新的线程,我可以看到最多有 20 个线程在运行(corepoolsize)并且没有拒绝异常,即提交的数量在队列的范围内。

任何想法为什么会发生这种情况?

提前致谢。

【问题讨论】:

  • 您是否在应用程序的任何位置更改线程优先级(来自池或其他)?这在不同的平台上可能会产生不同的效果。
  • 没有。没有为线程明确设置优先级。
  • 我正在使用 Java 1.6.0_18(64 位服务器 VM(内部版本 16.0-b13,混合模式)。服务器操作系统 - Linux - 2.6.27.9。
  • ThreadPool 线程是否受计算约束? IE。它们是否处于没有外部交互且运行很长时间的紧密循环中?如果是这种情况,您可能需要偶尔致电Thread#yield()
  • 处理器线程基本上连接到数据库并将消息发送给客户端。这些过程本身不需要更长的时间。问题在于较旧的线程,如果没有我的实现,它们的工作速度非常快。在我为应用程序的一部分实现 ThreadPoolExecutor 之后,其他线程正在延迟。

标签: java threadpool executors


【解决方案1】:

我之前使用 Linux 线程的经验清楚地表明,与在相同负载下运行在 Windows 中的相同系统相比,它在非常繁忙时更容易出现线程饥饿。我编写了一个测试程序,表明在 CPU 负载较重的情况下,当使用标准等待/通知原语 - IIRC 时,一些线程将获得比其他线程更多的 CPU 时间,数量级。我的解决方案是在公平模式下使用可重入锁来循环它们。

再次,IIRC,在每个工作事件结束时输入Thread.yield 没有积极影响。

所有这些都可能受到您的 Linux 发行版使用的几个线程库中的哪一个的显着影响。

您可以通过向主导工作负载的工作队列添加一个节流器来获得一些改进,但最好能以某种方式适应其他不相关线程上待处理的工作量。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-12-26
    • 1970-01-01
    • 1970-01-01
    • 2021-05-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-19
    相关资源
    最近更新 更多