109

我想用 Java 中的多个线程解决数学问题。我的数学问题可以分成几个工作单元,我想在几个线程中解决。

我不想让固定数量的线程在上面工作,而是让线程数量与 CPU 内核的数量相匹配。我的问题是,我在互联网上找不到一个简单的教程。我发现的只是固定线程的例子。

如何才能做到这一点?你能提供例子吗?

4

6 回答 6

120

您可以使用静态运行时方法 availableProcessors 来确定 Java 虚拟机可用的进程。一旦您确定了可用的处理器数量,就创建该数量的线程并相应地拆分您的工作。

更新:为了进一步澄清,线程只是 Java 中的一个对象,因此您可以像创建任何其他对象一样创建它。因此,假设您调用上述方法并发现它返回 2 个处理器。惊人的。现在,您可以创建一个循环来生成一个新线程,并为该线程拆分工作,并触发该线程。这是一些伪代码来演示我的意思:

int processors = Runtime.getRuntime().availableProcessors();
for(int i=0; i < processors; i++) {
  Thread yourThread = new AThreadYouCreated();
  // You may need to pass in parameters depending on what work you are doing and how you setup your thread.
  yourThread.start();
}

有关创建自己的线程的更多信息,请参阅本教程。此外,您可能希望查看线程池以创建线程。

于 2009-12-30T15:51:50.020 回答
65

你可能也想看看 java.util.concurrent 框架。就像是:

ExecutorService e = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
// Do work using something like either
e.execute(new Runnable() {
        public void run() {
            // do one task
        }
    });

或者

    Future<String> future = pool.submit(new Callable<String>() {
        public String call() throws Exception {
            return null;
        }
    });
    future.get();  // Will block till result available

这比处理自己的线程池等要好得多。

于 2009-12-30T16:03:53.680 回答
11

选项1:

newWorkStealingPool来自Executors

public static ExecutorService newWorkStealingPool()

创建一个工作窃取线程池,使用所有可用的处理器作为其目标并行级别。

使用此 API,您无需将核心数传递给ExecutorService.

从grepcode实现这个 API

/**
     * Creates a work-stealing thread pool using all
     * {@link Runtime#availableProcessors available processors}
     * as its target parallelism level.
     * @return the newly created thread pool
     * @see #newWorkStealingPool(int)
     * @since 1.8
     */
    public static ExecutorService newWorkStealingPool() {
        return new ForkJoinPool
            (Runtime.getRuntime().availableProcessors(),
             ForkJoinPool.defaultForkJoinWorkerThreadFactory,
             null, true);
    }

选项 2:

Executors来自or的newFixedThreadPool API other newXXX constructors,它返回ExecutorService

public static ExecutorService newFixedThreadPool(int nThreads)

将 nThreads 替换为 Runtime.getRuntime().availableProcessors()

选项 3:

线程池执行器

public ThreadPoolExecutor(int corePoolSize,
                      int maximumPoolSize,
                      long keepAliveTime,
                      TimeUnit unit,
                      BlockingQueue<Runnable> workQueue)

Runtime.getRuntime().availableProcessors()作为参数传递给maximumPoolSize.

于 2016-04-19T15:48:44.470 回答
8

Doug Lea(并发包的作者)有这篇可能相关的论文:http: //gee.cs.oswego.edu/dl/papers/fj.pdf

Java SE 7 中添加了 Fork Join 框架。以下是更多参考资料:

http://www.ibm.com/developerworks/java/library/j-jtp11137/index.html Brian Goetz 的文章

http://www.oracle.com/technetwork/articles/java/fork-join-422606.html

于 2009-12-30T19:22:38.113 回答
4

标准方法是 Runtime.getRuntime().availableProcessors() 方法。在大多数标准 CPU 上,您将在此处返回最佳线程数(这不是实际的 CPU 核心数)。因此,这就是您要寻找的。

例子:

ExecutorService service = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());

不要忘记像这样关闭执行器服务(否则您的程序将不会退出):

service.shutdown();

这里只是一个快速概述如何设置基于未来的 MT 代码(题外话,用于说明):

CompletionService<YourCallableImplementor> completionService = 
    new ExecutorCompletionService<YourCallableImplementor>(service);
    ArrayList<Future<YourCallableImplementor>> futures = new ArrayList<Future<YourCallableImplementor>>();
    for (String computeMe : elementsToCompute) {
        futures.add(completionService.submit(new YourCallableImplementor(computeMe)));
    }

然后,您需要跟踪您期望的结果数量并像这样检索它们:

try {
  int received = 0;
  while (received < elementsToCompute.size()) {
     Future<YourCallableImplementor> resultFuture = completionService.take(); 
     YourCallableImplementor result = resultFuture.get();
     received++; 
  }
} finally {
  service.shutdown();
}
于 2015-11-02T21:23:58.123 回答
3

在 Runtime 类上,有一个名为 availableProcessors() 的方法。你可以用它来计算你有多少个 CPU。由于您的程序受 CPU 限制,您可能希望(至多)每个可用 CPU 有一个线程。

于 2009-12-30T15:51:21.457 回答