ThreadPoolExecutor 线程与其他线程存在争用
我正在致力于对现有 Java 应用程序进行增强。该应用程序是一个消息处理器,每天处理数百万条消息。它基本上是使用 Core Java 编写的,线程和队列是使用 Collection 类实现的。
在此应用程序中,某些类型的消息在单个线程中运行。我的任务是使应用程序的这个特定部分成为多线程,以便更快地处理消息,因为我们有双处理器。
由于我们使用的是 Java 5,因此我采用了使用 ThreadPoolExcecutor 的方法。我为每个客户端创建了处理器线程,以便可以在其自己的线程中处理特定线程的消息。处理器线程正在实现 Callable 接口,因为这将允许我检查未来对象是否完成前一个任务。
在初始化过程中,我将检查所有客户端并为每个客户端创建处理器线程,并使用它们的 id 作为唯一键将其存储在映射中。为了跟踪以前提交的作业,我再次使用相同的 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() {
....
....
}
}
问题
上面的实现在我的测试环境中运行良好。但是,在生产环境(Edit#1 - Ubuntu、Linux Slackware、Java - 1.6.0_18)中,我们观察到应用程序的其他线程不通过此管理新的 ThreadpoolExecutor 受到影响。即,他们的任务被延迟了几个小时。是否因为 ThreadPoolExecutors 创建的线程占用了全部资源或其他资源,并且没有给其他线程机会。
使用 ThreadPoolExceutor 创建的新线程正在执行独立的任务,不会与其他线程争夺资源。即,不存在竞争条件场景。
在日志中,对于新线程,我可以看到最多有20个线程正在运行(corepoolsize),并且没有拒绝异常,即提交数量在队列范围内。
有什么想法为什么会发生这种情况吗?
提前致谢。
I am working on a enhancement for an existing Java application. The application is a message processor which processes several millions of messages daily. It basically written using Core Java with threads and queues are implemented using Collection classes.
In this application some type of the messages are running in a single thread. I was given the task to make this particular part of the application to multi threaded to process the messages faster, as we have dual processors.
Since we are using Java 5, I took the approach of using ThreadPoolExcecutor. I have created processor threads for each clients so that message for a particular threads can be processed in its own thread. The processor threads are implementing Callable interface as this will allow me to check the future object whether the previous task is finished or not.
During initialization process, I will go over all the clients and create processor threads for each and store it in map using their id as unique key. To track previously submitted job, I do keep the future object in another map again using same id as unique key.
Below are some snippet of code which I used : In main class -
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);
}
}
Processor Thread
public class MyProcessor implements Callable<String> {
.....
.....
public String call() {
....
....
}
}
The Issue
The above implementation is working good in my test environment. However, in production environment (Edit#1 - Ubuntu, Linux Slackware, Java - 1.6.0_18), we observed that other threads of the application which are not managed through this new ThreadpoolExecutor are getting affected. i.e., their tasks are getting delayed for hours. Is it because the threads created by ThreadPoolExecutors are taking the whole resources or whatsoever and not giving the chance to other threads.
The new threads created using ThreadPoolExceutor are doing independent task and are not in contention with other thread for resources. i.e., there is no race condition scenario.
In the log, for the new Threads, I can see that there are maximum of 20 threads running (corepoolsize) and there are no rejection exceptions, i.e., the number of submits are within the bounds of the queue.
Any ideas why this is happening?
Thanks in advance.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我之前使用 Linux 线程的经验清楚地表明,在非常繁忙的情况下,与在相同负载下在 Windows 中运行的相同系统相比,它更容易出现线程匮乏的情况。我编写了一个测试程序,该程序表明,在 CPU 负载较重的情况下,使用标准等待/通知原语 - IIRC 时,一些线程将比其他线程获得更多的 CPU 时间,高出一个数量级。我的解决方案是在公平模式下使用可重入锁来循环它们。
同样,IIRC 在每个工作事件结束时添加 Thread.yield 并没有产生任何积极效果。
所有这些都可能会受到您的 Linux 发行版使用的几个线程库的显着影响。
通过向主宰工作负载的工作队列添加节流器,您可能会得到一些改进,尽管最好是能够以某种方式适应其他不相关线程上待处理的工作量。
My prior experience with Linux threading showed clearly that it is much more prone to thread starvation when very busy than the same system running in Windows under the same load. I wrote a test program that indicated that under heavy CPU load a few threads will get far more CPU time than the others when using the standard wait/notify primitives - IIRC, by an order of magnitude. My solution was to use a reentrant lock in fair mode to round robin them.
Again, IIRC, throwing in
Thread.yield
at the conclusion of each work event had no positive effect.All of this may be significantly impacted by which of the several threading libraries your Linux distro is using.
You may get some improvement by adding a throttler to the work queue which is dominating the work-load, though it would be best if that were somehow adaptive to the amount of work pending on the other unrelated threads.