Nos*_*ama 66 java concurrency multithreading multicore
我正在编写一个使用大量CPU的Java程序,因为它的功能本质.但是,很多都可以并行运行,而且我的程序是多线程的.当我运行它时,它似乎只使用一个CPU,直到它需要更多然后它使用另一个CPU - 我有什么可以用Java来强制不同的线程在不同的核心/ CPU上运行吗?
Bob*_*Gee 56
Java中有多种基本的多线程方法.使用这些方法创建的每个逻辑任务都应在需要和可用时在新核心上运行.
方法一:定义一个Runnable或Thread对象(可以在构造函数中使用Runnable)并使用Thread.start()方法启动它.它将在操作系统提供的任何核心上执行 - 通常是负载较少的核心.
教程:定义和启动线程
方法二:定义实现Runnable的对象(如果它们不返回值)或Callable(如果它们)接口,它们包含您的处理代码.将这些作为任务从java.util.concurrent包传递给ExecutorService.java.util.concurrent.Executors类有许多方法来创建标准的,有用的ExecutorServices类.链接到执行者教程.
根据个人经验,Executors修复和缓存的线程池非常好,但您需要调整线程数.可以在运行时使用Runtime.getRuntime().availableProcessors()来计算可用内核.应用程序完成后,您需要关闭线程池,否则应用程序将不会退出,因为ThreadPool线程保持运行.
获得良好的多核性能有时很棘手,并且充满了问题:
另一个问题是:控制工作很难!一个好的做法是让一个管理器线程创建并提交任务,然后是一些工作线程与工作队列(使用ExecutorService).
我只是在谈论关键点 - 多线程编程被许多专家认为是最难编程的主题之一.它不直观,复杂,抽象通常很弱.
编辑 - 使用ExecutorService的示例:
public class TaskThreader {
class DoStuff implements Callable {
Object in;
public Object call(){
in = doStep1(in);
in = doStep2(in);
in = doStep3(in);
return in;
}
public DoStuff(Object input){
in = input;
}
}
public abstract Object doStep1(Object input);
public abstract Object doStep2(Object input);
public abstract Object doStep3(Object input);
public static void main(String[] args) throws Exception {
ExecutorService exec = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
ArrayList<Callable> tasks = new ArrayList<Callable>();
for(Object input : inputs){
tasks.add(new DoStuff(input));
}
List<Future> results = exec.invokeAll(tasks);
exec.shutdown();
for(Future f : results) {
write(f.get());
}
}
}
Run Code Online (Sandbox Code Playgroud)
Zan*_*ynx 18
首先,您应该向自己证明您的程序在多个内核上运行得更快.许多操作系统尽可能地在同一个核心上运行程序线程.
在同一核心上运行有许多优点.CPU缓存很热,这意味着该程序的数据被加载到CPU中.锁定/监视/同步对象位于CPU缓存中,这意味着其他CPU不需要在总线上执行缓存同步操作(非常昂贵!).
有一件事可以很容易地让你的程序一直在同一个CPU上运行,就是过度使用锁和共享内存.你的线程不应该互相交谈.线程在同一内存中使用相同对象的频率越低,它们在不同CPU上运行的频率就越高.他们使用相同内存的次数越多,他们就越需要阻止等待其他线程.
每当操作系统看到另一个线程的一个线程块时,它就会在同一个CPU上运行该线程.它减少了在CPU间总线上移动的内存量.这就是我猜你在程序中看到的结果.
首先,我建议阅读Brian Goetz的"实践中的并发".
这是迄今为止描述并发java编程的最佳书籍.
并发性"易于学习,难以掌握".在尝试之前,我建议阅读有关该主题的大量内容.很容易让多线程程序在99.9%的时间内正常工作,并且失败率为0.1%.但是,这里有一些提示可以帮助您入门:
有两种常用方法可以使程序使用多个核心:
在最低级别,可以创建和销毁线程.Java使得以便携式跨平台方式创建线程变得容易.
由于创建和销毁线程的成本往往很高,Java现在包括Executors来创建可重用的线程池.可以将任务分配给执行程序,并且可以通过Future对象检索结果.
通常,一个人可以将任务划分为较小的任务,但最终结果需要重新组合在一起.例如,使用合并排序,可以将列表划分为越来越小的部分,直到每个核心都进行排序.但是,由于每个子列表都已排序,因此需要将其合并以获取最终的排序列表.由于这是"分而治之"的问题相当普遍,因此有一个JSR框架可以处理底层分发和加入.该框架可能包含在Java 7中.