论坛首页 Java企业应用论坛

淘宝面试题:如何充分利用多核CPU,计算很大的List中所有整数的和

浏览 94262 次
该帖已经被评为良好帖
作者 正文
   发表时间:2010-07-13  
   int len=list.size()/threadCounts;//平均分割List 
        for(int i=0;i<threadCounts;i++){ 
            //创建线程任务 
            exec.execute(new SubIntegerSumTask(list.subList(i*len, len*(i+1)))); 
        }
这个好像不能将所有的list全部运行完吧 如果int len=list.size()/threadCounts不能整除是个近似数的话 就有问题了
0 请登录后投票
   发表时间:2010-07-13  
hrsvici412 写道
学到好多线程的东西,请问 你的分析的图,是用什么工具画的!

好像是office2007or2010 里面有一个好像就叫流程图的东西~
0 请登录后投票
   发表时间:2010-07-13  
<code>
ExecutorService exec=Executors.newFixedThreadPool(threadCounts);  
        int len=list.size()/threadCounts;//平均分割List  
        for(int i=0;i<threadCounts;i++){  
           //创建线程任务  
            exec.execute(new SubIntegerSumTask(list.subList(i*len, len*(i+1))));  
       } 
</code>
这段是不是有点问题, int len=list.size()/threadCounts你确保正好整除吗?
0 请登录后投票
   发表时间:2010-07-13  
另外,个人感觉这里用CountDownLatch比用CyclicBarrier更合适点,这个案例只需要主线程等待子线程,各子线程间不需要相互等待,子线程求和完成后可以立即输出并结束。
0 请登录后投票
   发表时间:2010-07-13  
xifo 写道
思路是对的,可惜算法有问题,大多数情况下计算结果不正确。

不信的话,试试把这一行
for (int i = 1; i <= 1000000; i++)

换成
for (int i = 0; i <= 1000000; i++)


如果计算正确,两个计算结果应该一样,实际上计算结果会少一百万,原因是分割那里没有考虑尾数。


你好细心哦,这都被你看出来了,确实,在分割的时候,分割的最后一组应该考虑一下不能整除情况下的余数,呵呵
0 请登录后投票
   发表时间:2010-07-13   最后修改:2010-07-13
以前写过类似这样的东西 但是没有CyclicBarrier类
ExecutorService 的 shutdown 方法应该在 barrier.await(); 前面

你的内部类实现 callable 接口 然后Call 会返回值
ExecutorService 的submit方法可以返回一个 Future 对象
Future 对象来实现同步很好用的 可以尝试下
用 Futrue 的 isDone 来判断线程是否工作结束
0 请登录后投票
   发表时间:2010-07-13  
个人也觉得使用CountDownLatch就可以了. 还有, 包含所有整数的List没必要拆分为一个个小的List, 只要算出各自计算的index范围, 第一计算1-100个, 第二个计算101-200个, 从同一个List中取值.
0 请登录后投票
   发表时间:2010-07-13  
顶,今天才知道了CyclicBarrier这个类。学习。。
看大家都这样说,楼主的分割好像有问题。
0 请登录后投票
   发表时间:2010-07-13   最后修改:2010-07-13
飞雪无情 写道
引用

本文主要通过一个淘宝的面试题为引子,介绍了并发的一点小知识,主要是介绍通过CyclicBarrier同步辅助器辅助多个并发任务共同完成一件工作。Java SE5的java.util.concurrent引入了大量的设计来解决并发问题,使用它们有助于我们编写更加简单而健壮的并发程序。

不用这么麻烦吧
用ExecutorService.invokeAll就行了吧。


嗯。。使用ExecutorService.invokeAll可以,不用认为的控制同步及其等待。但是使用CyclicBarrier有它的好处,关键就是方便灵活,可以控制什么时候进行等待。下面是使用ExecutorService.invokeAll实现的方法,运行结果是一样的:
/**
 * 使用ExecutorService的invokeAll方法计算
 * @author 飞雪无情
 *
 */
public class CountSumWithCallable {

	/**
	 * @param args
	 * @throws InterruptedException 
	 * @throws ExecutionException 
	 */
	public static void main(String[] args) throws InterruptedException, ExecutionException {
		int threadCounts =20;//使用的线程数
		long sum=0;
		ExecutorService exec=Executors.newFixedThreadPool(threadCounts);
		List<Callable<Long>> callList=new ArrayList<Callable<Long>>();
		//生成很大的List
		List<Integer> list = new ArrayList<Integer>();
		for (int i = 1; i <= 1000000; i++) {
			list.add(i);
		}
		int len=list.size()/threadCounts;//平均分割List
		//List中的数量没有线程数多(很少存在)
		if(len==0){
			threadCounts=list.size();//采用一个线程处理List中的一个元素
			len=list.size()/threadCounts;//重新平均分割List
		}
		for(int i=0;i<threadCounts;i++){
			final List<Integer> subList;
			if(i==threadCounts-1){
				subList=list.subList(i*len,list.size());
			}else{
				subList=list.subList(i*len, len*(i+1)>list.size()?list.size():len*(i+1));
			}
			//采用匿名内部类实现
			callList.add(new Callable<Long>(){
				public Long call() throws Exception {
					long subSum=0L;
					for(Integer i:subList){
						subSum+=i;
					}
					System.out.println("分配给线程:"+Thread.currentThread().getName()+"那一部分List的整数和为:\tSubSum:"+subSum);
					return subSum;
				}
			});
		}
		List<Future<Long>> futureList=exec.invokeAll(callList);
		for(Future<Long> future:futureList){
			sum+=future.get();
		}
		exec.shutdown();
		System.out.println(sum);
	}

}

0 请登录后投票
   发表时间:2010-07-13  
很好的列子,后面大家补充的算法漏洞也很精彩
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics