java中的负载均衡线程池

时间:2013-01-19 14:26:40

标签: java multithreading threadpool pool

我正在寻找一个负载均衡的线程池,到目前为止没有成功。 (不确定负载平衡是否是正确的措辞)。 让我解释一下我试图实现的目标。

第1部分: 我有乔布斯,有8到10个单一任务。在6核CPU上,让8个线程并行处理这个任务,这似乎可以提供最佳的性能。当一个任务准备就绪时,另一个任务就可以开始。完成所有十项任务后,完成整个工作。通常工作在30至60秒内完成。

第二部分: 有些时候,不幸的是,这项工作需要两个多小时。由于必须计算的数据量,这是正确的。 坏的是,在job1运行时没有其他工作可以启动(假设所有线程具有相同的持续时间),因为它正在使用所有线程。

我的第一个想法: 有12个线程,并行允许最多三个作业。 但是:这意味着,当只有一份工作时,这项工作就没有完全实现。

我正在寻找一种解决方案,在没有其他工作的情况下为作业1提供全部CPU能力。但是当另一个工作需要在另一个工作时启动时,我希望将CPU功率分配给这两个工作。当第三或第四个工作出现时,我希望cpu power能够公平地分配给所有四个工作。

我赞成你的答案......

提前致谢

3 个答案:

答案 0 :(得分:6)

一种可能性是使用具有不同类型任务队列的标准ThreadPoolExecutor

public class TaskRunner {
  private static class PriorityRunnable implements Runnable,
            Comparable<PriorityRunnable> {
    private Runnable theRunnable;
    private int priority = 0;
    public PriorityRunnable(Runnable r, int priority) {
      this.theRunnable = r;
      this.priority = priority;
    }

    public int getPriority() {
      return priority;
    }

    public void run() {
      theRunnable.run();
    }

    public int compareTo(PriorityRunnable that) {
      return this.priority - that.priority;
    }
  }

  private BlockingQueue<Runnable> taskQueue = new PriorityBlockingQueue<Runnable>();

  private ThreadPoolExecutor exec = new ThreadPoolExecutor(8, 8, 0L,
            TimeUnit.MILLISECONDS, taskQueue);

  public void runTasks(Runnable... tasks) {
    int priority = 0;
    Runnable nextTask = taskQueue.peek();
    if(nextTask instanceof PriorityRunnable) {
      priority = ((PriorityRunnable)nextTask).getPriority() + 1;
    }
    for(Runnable t : tasks) {
      exec.execute(new PriorityRunnable(t, priority));
      priority += 100;
    }
  }
}

这里的想法是,当你有一份新工作时,你可以打电话

taskRunner.runTasks(jobTask1, jobTask2, jobTask3);

它将以这样的方式排队任务:它们与队列中的任何现有任务(如果有的话)很好地交错。假设你有一个排队的工作,其任务有优先级数j 1 t 1 = 3,j 1 t 2 = 103,并且j 1 t 3 = 203。在没有其他工作的情况下,这些任务将尽快一个接一个地执行。但是如果你提交另一个有三个任务的工作,这些工作将被分配优先级数j 2 t 1 = 4,j 2 t 2 = 104且j 2 t 3 = 204,这意味着队列现在看起来像

j 1 t 1 ,j 2 t 1 ,j 1 t 2 ,j 2 t 2 等。

然而,这并不完美,因为如果所有线程当前都在工作(来自作业1的任务),则作业2的第一个任务无法启动,直到其中一个作业1任务完成(除非有一些外部方式你要检测到这一点并中断并重新排队一些作业1的任务)。使事情更公平的最简单方法是将较长时间运行的任务分解为较小的段并将它们排列为单独的任务 - 您需要达到每个单独的工作涉及的任务多于池中的线程,因此,某些任务将始终在队列中启动,而不是直接分配给线程(如果有空闲线程,则exec.execute()将任务直接传递给线程而不通过队列。

答案 1 :(得分:1)

我认为既然你的机器是6核CPU。每个作业线程最好有6个工作线程。因此,当一个线程获得一个新工作时,它会启动多达六个并行工作者来处理单个工作。这将确保在一次只有一个作业时消耗全部CPU功率。

另请参阅java 7中的Fork and Join概念 References_1
References_2
References_3 References_4

还要了解newcachedthreadpool()

Java newCachedThreadPool() versus newFixedThreadPool

答案 2 :(得分:1)

最简单的做法是过度订阅你的CPU,正如Kanaga建议的那样,但每个都要启动8个线程。竞争对手可能会有一些开销,但如果你遇到单一的工作情况,它将充分利用CPU。操作系统将处理给每个线程的时间。

你的“第一个想法”也会奏效。如果空闲线程实际上没有执行任务,则它们不会从8个工作线程中获取资源。但是,当有多个作业在运行时,这不会均匀地分配cpu资源。

您是否有可以测试这些不同管道的设置,以了解它们的效果如何?