ThreadPoolExecutor线程与其他线程争用

时间:2011-03-31 23:47:53

标签: java threadpool executors

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

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

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

在初始化过程中,我将遍历所有客户端并为每个客户端创建处理器线程,并使用其id作为唯一键将其存储在map中。要跟踪以前提交的作业,我会使用相同的ID作为唯一键将未来对象再次保存在另一个地图中。

下面是我使用的一些代码片段:在主要类 -

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() {
        ....
        ....
    }
 }

问题

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

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

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

为什么会发生这种情况?

提前致谢。

1 个答案:

答案 0 :(得分:0)

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

同样,IIRC在每次工作结束时投掷Thread.yield没有产生任何积极影响。

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

您可以通过向工作队列中添加一个限制器来获得一些改进,但是如果它在某种程度上适应其他无关线程上待处理的工作量,那么最好是这样做。