假设我有一个List
个整数。每个int
我必须乘以100
。要使用for
循环执行此操作,我将构建如下内容:
for(Integer i : numbers){
i = i*100;
}
但是假设出于性能原因,我想同时为numbers
中的每个数字生成一个线程,并在每个线程上执行一次乘法,将结果返回到相同的List
。这样做的最佳方式是什么?
我的实际问题并不像int
的乘法那样微不足道,而是循环的每次迭代花费大量时间的任务,所以我想在同一时间完成所有这些时间,以减少执行时间。
答案 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()返回的线程池。然后创建将Runnable和submit()
实现到您的线程池的任务。还要阅读那些由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]范围内。加上共享列表上的争用。
但更重要的是,产生新线程的成本远远高于进行乘法的成本。一个人可能有一个线程池...但在这个特定的情况下,它甚至不值得谈论它。真。