假设我有一组需要以两种不同方式进行分析的对象,这两种方式都需要相对较长的时间并涉及IO调用,我试图弄清楚如何/如果我可以优化这部分我的软件,特别是使用多个处理器(我所使用的机器是一个8核的i7,在执行过程中几乎不会超过10%的负载)。
我对并行编程或多线程很不熟悉(不确定正确的术语是什么),所以我已经阅读了一些先前的问题,特别是关注高度投票和信息丰富的答案。我也正在浏览Oracle/Sun tutorial on concurrency。
这是我到目前为止的想法;
我的问题是:
谢谢,
答案 0 :(得分:3)
你的想法基本上是健全的。但是,不是直接创建线程,也不是通过您自己设计的某种ThreadManager间接创建线程,而是使用Java的并发包中的Executor。它可以满足您的所有需求,其他人已经花时间编写和调试它。执行程序管理任务队列,因此您无需担心自己提供线程安全队列。
Callable和Runnable之间没有区别,前者返回一个值。执行者将处理这两种情况,并为它们做好准备。
我不清楚您是否计划将准备步骤作为分析的单独任务,或将其折叠成其中一个,该任务将在中途产生另一个分析任务。我想不出有任何理由强烈倾向于彼此,但这是你应该考虑的选择。
答案 1 :(得分:3)
您可以使用BlockingQueue实现来保存对象并从那里生成线程。此接口基于 producer-consumer 原则。如果队列已满,put()方法将阻塞,直到有更多空间,如果队列为空,take()方法将阻塞,直到队列中再次存在某些对象为止。
< / LI>ExecutorService可以帮助您管理线程池。
如果您正在等待生成的线程的结果,那么 Callable 接口是一个好主意,因为您可以提前开始计算并在代码中工作,假设结果在未来 -s。至于 Runnable 界面的差异,来自Callable javadoc:
Callable接口类似于Runnable,因为它们都是为其实例可能由另一个线程执行的类而设计的。但是,Runnable不会返回结果,也不能抛出已检查的异常。
在寻求Java并发时需要考虑的一些常见问题:
答案 2 :(得分:2)
Executors提供了用于创建线程池的工厂方法。具体来说,执行程序#newFixedThreadPool(int nThreads)创建一个使用无界队列的固定大小的线程池。此外,如果线程因故障而终止,则新线程将被替换。因此,在您的256个任务和16个线程的具体示例中,您可以调用
// create pool
ExecutorService threadPool = Executors.newFixedThreadPool(16);
// submit task.
Runnable task = new Runnable(){};;
threadPool.submit(task);
重要的问题是确定线程池的正确线程数。看看这有助于Efficient Number of Threads
答案 3 :(得分:0)
听起来很合理,但实施起来并不像看起来那么简单。 也许你应该检查一下jsr166y项目。 这可能是解决问题的最简单方法。