500个工作线程,需要哪种线程池?

8

我在想这是否是最佳的做法。我有大约500个线程无限运行,但在完成一个处理周期后会休眠一分钟。

   ExecutorService es = Executors.newFixedThreadPool(list.size()+1);
   for (int i = 0; i < list.size(); i++) {
      es.execute(coreAppVector.elementAt(i)); //coreAppVector is a vector of extends thread objects
   }

正在执行的代码非常简单,基本上只有这个。
class aThread extends Thread {
   public void run(){
      while(true){
         Thread.sleep(ONE_MINUTE);
         //Lots of computation every minute
      }
   }
}

我需要为每个正在运行的任务单独创建一个线程,因此改变架构不是一个选项。我尝试将我的线程池大小设置为Runtime.getRuntime().availableProcessors(),以尝试运行所有500个线程,但仅允许其中8个(4x超线程)执行。其他线程不会放弃并让其他线程轮流执行。我尝试使用wait()和notify(),但是仍然没有运气。如果有人有一个简单的示例或一些技巧,我将非常感激!
嗯,设计可以说是有缺陷的。这些线程实现了遗传编程或GP,一种学习算法。每个线程分析高级趋势并进行预测。如果线程完成,学习就会丢失。也就是说,我希望sleep()能够在一个线程“不学习”时允许我共享一些资源。
因此,实际要求是:如何安排维护状态并每2分钟运行一次的任务,但控制同时执行的数量。

2
我不清楚你想做什么。 为什么不尝试运行所有线程呢?就像这样:for(int i....) { ((Thread)coreAppVector.elementAt(i)).start(); } - Andrea Polci
3
这里的现实情况是,使用500个线程需要比使用8个线程花费更长的时间。只有8个独立处理器会导致大量的上下文切换,这将导致每个2秒的计算时间变得更长。 - John Vint
2
您的情况下,500个线程至少太多了492个。因为您正在使用超线程技术,实际上并没有8个真正的CPU。我建议您使用轮询配置中的4个线程,这样可能可以获得最佳性能。 - Daniel Pryden
1
但是它们一定要是Thread对象吗?您可以将它们设置为Runnable并让它们保留此重要的内部状态,然后根据系统可管理的线程数量,在适当的时候调用run方法,这个数量可能超过4或8,如果任务的一部分被阻塞在网络/数据库/任何IO上。 - Affe
1
仅仅因为有八个(逻辑)核心,并不意味着最佳性能将来自于八个线程。如果线程是CPU绑定的,那么八个线程会更接近正确,但如果线程是IO绑定的,那么拥有更多的线程可能是有意义的。总体上同意这个想法,但必须小心控制上下文切换。 - user41871
显示剩余14条评论
11个回答

-1

通过将线程数减少到系统实际可处理的数量,您肯定可以提高吞吐量。您是否愿意稍微更改线程的设计?这将使调度程序不再负担沉重,而是将休眠的线程放入队列中,而不是实际上有数百个休眠线程。

class RepeatingWorker implements Runnable {

private ExecutorService executor;
private Date lastRan;

//constructor takes your executor

@Override
public void run() {

  try {
    if (now > lastRan + ONE_MINUTE) {
      //do job
      lastRan = now;
    } else {
      return;
  } finally {
    executor.submit(this);
  }
}
}

这样可以保留您的核心语义:“作业无限重复,但在执行之间至少等待一分钟”,但现在您可以调整线程池以适应机器处理的情况,并且那些不工作的线程将排队而不是在调度程序中徘徊作为睡眠线程。如果实际上没有人在做任何事情,会有一些等待繁忙的行为,但我假设根据您的帖子,应用程序的整个目的是运行这些线程,并且它当前正在使用您的处理器。如果必须为其他事情腾出空间,则可能需要进行调整 :)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接