论坛首页 Java企业应用论坛

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

浏览 94792 次
该帖已经被评为良好帖
作者 正文
   发表时间:2011-03-28  
额。。。看错了。。。 都对
0 请登录后投票
   发表时间:2011-03-29  
我觉得这种东西迟早都会过时的,靠程序员在代码中体现多核技术,就跟当年程序员手动分配内存一样,迟早会变成过去式。
0 请登录后投票
   发表时间:2011-03-29   最后修改:2011-03-29
没有必要这么麻烦的
如果提交任务数与固定线程池线程数相等的话


pool.shutdown()

while(!pool.isTerminated()){
   // sleep 500L
}

sysout(sum);



shutdown会等待所有正在执行的任务执行完毕
isTerminated直到调用shutdown且所有任务complete才会返回true

当然 上述代码的前提是提交任务数<=固定线程池线程数
0 请登录后投票
   发表时间:2011-05-19  
本题的目的大家都清楚,利用java多线程来充分利用多CPU或多核。具体方案如下:
1.多线程,线程数目已经有人提到过,最佳的线程数应该是跟CPU核相关,调用Runtime.getRuntime().availableProcessors获取处理器数。
2.很多人采用拆分List,我的观点是不拆分。调用List.size,平均分配索引范围给多个线程。
3.每个线程按索引范围依次统计。最后主线程等待其他线程统计完成后最终统计值。
package com.webex.dms2.components.zk.common;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

import org.apache.commons.lang.math.RandomUtils;

public class ListCounter {
	private static List dataPrepair(int listSize) {
		List<Integer> list = new ArrayList<Integer>(listSize);
		for (int i = 0; i < listSize; i++) {
			list.add(RandomUtils.nextInt());
		}
		return list;
	}

	public static void main(String[] args) throws Exception {
		int threadNum = Runtime.getRuntime().availableProcessors();
		int listSize = 10000000;
		final List<Integer> list = dataPrepair(listSize);
		int threadListSize = listSize / threadNum;
		assert listSize > threadNum;
		final int[] dataRange = new int[threadNum];
		for (int i = 0; i < threadNum - 1; i++) {
			dataRange[i] = threadListSize * (i + 1);
		}
		dataRange[threadNum - 1] = listSize;
		ExecutorService executor = Executors.newFixedThreadPool(threadNum);
		Future<Long>[] results = new Future[threadNum];
		for (int i = 0; i < threadNum; i++) {
			results[i] = executor.submit(new CounterTask(dataRange[i]
					- threadListSize, dataRange[i], list));
		}
		long total = 0l;
		for (int i = 0; i < threadNum; i++) {
			total += results[i].get();
		}
		System.out.println("the list total sum:" + total);
		executor.shutdown();

	}

	private static class CounterTask implements Callable<Long> {
		final private int lowerLimit;
		final private int upperLimit;
		final private List<Integer> list;

		public CounterTask(int lowerLimit, int upperLimit,
				List<Integer> counteredList) {
			this.lowerLimit = lowerLimit;
			this.upperLimit = upperLimit;
			this.list = counteredList;
		}

		@Override
		public Long call() throws Exception {
			long total = 0;
			for (int i = lowerLimit; i < upperLimit; i++) {
				total += list.get(i);
			}
			return total;
		}

	}

}


0 请登录后投票
   发表时间:2011-05-19  
每次看到 “飞雪无情 ” 的帖子 貌似我都能有些收获这次也不例外!
0 请登录后投票
   发表时间:2011-05-20  
JDK7的 fork/jion框架 能很好地解决这类问题。
0 请登录后投票
   发表时间:2011-05-20   最后修改:2011-05-20
我来个:
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;

public class TestSum {
    private static final int           cpu             = 8;
    private static ExecutorService     executorService = Executors.newFixedThreadPool(cpu);
    private static AtomicInteger       taskCounter     = new AtomicInteger(0);
    private static int                 indexCounter    = 0;
    private static Set<Long>           tmpResultSet    = new HashSet<Long>();
    private static final List<Integer> ints            = new ArrayList<Integer>();

    private TestSum() {
    }

    public static void main(String[] args) {
        //构建测试数据开始
        final int count = 25702301;//我的笔记本最多能承受 值,过大就OOM =.=
        for (int i = 0; i < count; i++) {
            int value = (int) (Math.random() * 100);
            ints.add(value);
        }
        //构建测试数据结束,开始求和
        /**
         * 假设为8核cpu,将整个list 虚拟地分别8段,每个线程负责一段的计算sum
         */
        final int avg = count / cpu;
        while (taskCounter.getAndIncrement() < cpu) {//保障只能起和cpu个数一样多的线程
            executorService.execute(new Runnable() {
                public void run() {
                    int curt = indexCounter++;
                    int min = avg * curt;
                    int max;
                    if (curt != (cpu - 1)) {
                        max = avg * (curt + 1);
                    } else {
                        max = count;
                    }
                    System.out.println(max);
                    long result = 0;
                    for (int i = min; i < max; i++) {
                        result = result + ints.get(i);
                    }
                    tmpResultSet.add(result);
                    if (tmpResultSet.size() == cpu) {
                       long finalResult = 0;
                        for (long curtTmpResult : tmpResultSet) {
                            finalResult = finalResult + curtTmpResult;
                        }
                        System.out.println("finalResult=" + finalResult);
                    }
                }
            });
        }
        executorService.shutdown();
    }
}
0 请登录后投票
论坛首页 Java企业应用版

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