为这样的情况动态生成线程Java

时间:2012-01-17 21:37:29

标签: java multithreading performance

假设我有一个List个整数。每个int我必须乘以100。要使用for循环执行此操作,我将构建如下内容:

for(Integer i : numbers){
  i = i*100;
}

但是假设出于性能原因,我想同时为numbers中的每个数字生成一个线程,并在每个线程上执行一次乘法,将结果返回到相同的List。这样做的最佳方式是什么?

我的实际问题并不像int的乘法那样微不足道,而是循环的每次迭代花费大量时间的任务,所以我想在同一时间完成所有这些时间,以减少执行时间。

7 个答案:

答案 0 :(得分:4)

如果您可以使用Java 7,则会为此问题创建Fork/Join框架。如果没有,则在this link处有一个JSR166(fork / join proposal)源代码。

基本上,您将为每个步骤创建一个任务(在您的情况下,对于数组中的每个索引)并将其提交给可以池化线程的服务(fork部分)。然后等待所有内容完成并合并结果(连接部分)。

使用服务而不是启动自己的线程的原因是创建线程可能会有开销,在某些情况下,您可能希望限制线程数。例如,如果您使用的是四CPU机器,那么同时运行四个以上的线程就没有多大意义。

答案 1 :(得分:2)

如果您的任务彼此独立,则可以使用Executors框架。 请注意,如果您创建的线程数不超过CPU核心数,则可以获得更高的速度。

样品:

class WorkInstance {
    final int argument;
    final int result;

    WorkInstance(int argument, int result) {
        this.argument = argument;
        this.result = result;
    }

    public String toString() {
        return "WorkInstance{" +
                "argument=" + argument +
                ", result=" + result +
                '}';
    }
}

public class Main {

    public static void main(String[] args) throws IOException, ExecutionException, InterruptedException {
        int numOfCores = 4;
        final ExecutorService executor = Executors.newFixedThreadPool(numOfCores);
        List<Integer> toMultiplyBy100 = Arrays.asList(1, 3, 19);
        List<Future<WorkInstance>> tasks = new ArrayList<Future<WorkInstance>>(toMultiplyBy100.size());
        for (final Integer workInstance : toMultiplyBy100)
            tasks.add(executor.submit(new Callable<WorkInstance>() {
                public WorkInstance call() throws Exception {
                    return new WorkInstance(workInstance, workInstance * 100);
                }
            }));

        for (Future<WorkInstance> result : tasks)
            System.out.println("Result: " + result.get());

        executor.shutdown();
    }
}

答案 2 :(得分:1)

生成一个新主题
  

数字中的每个数字

不是个好主意。但是,使用大小与内核/ CPU数相匹配的固定线程池可能会略微提高性能。

答案 3 :(得分:1)

快速而又脏的方法是使用线程池,例如Executors.newCachedThreadPool()返回的线程池。然后创建将Runnablesubmit()实现到您的线程池的任务。还要阅读那些由Javadocs链接的类和接口,你可以尝试很多很酷的东西。

有关多线程Java的详细介绍,请参阅Effective Java, 2nd ed中的并发章节。

答案 4 :(得分:0)

如果它是节点上的唯一应用程序,则应确定哪个线程数最快将完成作业(max_throughput)。这取决于您使用的处理器JIT可以优化您的代码的程度,因此没有一般建议而是衡量。

之后,您可以通过numbers modulo max_throughput

将作业分发到工作线程池中

答案 5 :(得分:0)

查看ThreadPoolExecutor并为每次迭代创建一个任务。先决条件是这些任务是独立的。

使用线程池允许您在每次迭代时创建一个任务,但只运行与线程一样多的任务,因为您希望减少线程数,例如减少核心数或线程数可用。创建大量线程会产生反作用,因为它们需要大量的上下文切换,这会影响性能。

答案 6 :(得分:0)

我假设你在商品电脑上。您的机器上最多可以同时执行N个线程,其中N是CPU的核心数,因此很可能在[1,4]范围内。加上共享列表上的争用。

但更重要的是,产生新线程的成本远远高于进行乘法的成本。一个人可能有一个线程池...但在这个特定的情况下,它甚至不值得谈论它。真。