java.util.concurrent用多个线程并行计算一个数组的和(升级版本)

普通情况下,我们使用Runnable作为主要的任务表示形式,可是Runnable是一种有非常大局限的抽象,run方法中仅仅能记录日志,打印,或者把数据汇总入某个容器(一方面内存消耗大,还有一方面须要控制同步,效率非常大的限制),总之不能返回运行的结果;

比方同一时候1000个任务去网络上抓取数据,然后将抓取到的数据进行处理(处理方式不定),
最好的方式就是提供回调接口,把处理的方式最为回调传进去;

可是如今我们有了更好的方式实现:CompletionService + Callable

为此你可以保存与每个任务相关联的Future,然后不断地调用 timeout为零的get,来检验Future是否完成。

这样做固然可以,但却相当乏味。

幸运的是,还有一个更好的方法:完成服务 (Completion service)。

CompletionService整合了Executor和BlockingQueue的功能。

你可以将Callable任务提交给它去执行,然 后使用类似于队列中的take和poll方法,在结果完整可用时获得这个结果,像一个打包的Future。 

ExecutorCompletionService是实现CompletionService接口的一个类,并将计算任务委托给一个Executor。

Callable

Callable的call方法能够返回运行的结果;

CompletionService

CompletionService将Executor(线程池)和BlockingQueue(堵塞队列)结合在一起,同一时候使用Callable作为任务的基本单元,整个过程就是生产者不断把Callable任务放入堵塞对了,Executor作为消费者不断把任务取出来运行,并返回结果;
优势:

  • a、堵塞队列防止了内存中排队等待的任务过多,造成内存溢出(毕竟一般生产者速度比較快,比方爬虫准备好网址和规则,就去运行了,运行起来(消费者)还是比較慢的)

  • b、CompletionService能够实现,哪个任务先运行完毕就返回,而不是按顺序返回,这样能够极大的提升效率;

package java多线程模拟并行计算框架;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.CompletionService;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorCompletionService;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
 
//用十个线程计算一个数组的和
class TaskWithResult1 implements Callable {
    private Integer[] ints;
 
    public TaskWithResult1(Integer[] ints) {
        this.ints = ints;
    }
 
    private int sumFromArray() {
        int result = 0;
        for (int a : this.ints) {
            result += a;
        }
        return result;
    }
 
    @Override
    public Integer call() throws Exception {
        return sumFromArray();
    }
}
 
public class Paiallel2 {
    public static Integer[] segArray(int start, int end, int[] array) {
        List result = new ArrayList();
        for (int i = start; i < end; i++) {
            result.add(array[i]);
        }
 
        Integer[] ary = result.toArray(new Integer[result.size()]);
 
        return ary;
    }
 
    public static int getSum(int[] array) {
        int result = 0;
        for (int i = 0; i < array.length; i++) {
            result += array[i];
        }
        return result;
    }
 
    public static void main(String[] args) throws InterruptedException,
            ExecutionException {
        ExecutorService exec = Executors.newFixedThreadPool(10);
        CompletionService cplSvc = new ExecutorCompletionService(exec);
 
        int[] array = { 300, 800, 89, 390, 892, 9384, 909, 1, 343, 5839, 939,
                43, 355, 323, 32, 55, 3, 3, 43, 5, 5, 45, 555, 554, 554, 555,
                545, 555, 553, 35, 2322, 332, 3232, 433, 344, 524, 245, 524,
                6565, 526 };
 
        for (int i = 0; i < 10; i++) {
            int incre = array.length / 10;
            int start = i * incre;
            int end = (i + 1) * incre;
            if (end > array.length)
                end = array.length;
            Integer[] prt = segArray(start, end, array);
 
            TaskWithResult1 calbTask = new TaskWithResult1(prt);
            if (!exec.isShutdown()) {
                cplSvc.submit(calbTask);
            }
        }
 
        int result = 0;
        for (int i = 0; i < 10; i++) {
            int partRst = cplSvc.take().get();
            result += partRst;
        }
        exec.shutdown();
        System.out.println("并行计算的结果:" + result);
 
        int result2 = getSum(array);
        System.out.println("单独计算的结果:" + result2);
 
    }
 
}

结果:

并行计算的结果:39751
单独计算的结果:39751

你可能感兴趣的:(java.util.concurrent用多个线程并行计算一个数组的和(升级版本))