java方法2数据求和_Java并发和多线程2:3种方式实现数组求和

本篇演示3个数组求和的样例。

样例1:单线程

样例2:多线程。同步求和(假设没有计算完毕。会堵塞)

样例3:多线程。异步求和(先累加已经完毕的计算结果)

样例1-代码

package cn.fansunion.executorservice;

public class BasicCaculator {

public static long sum(int[] numbers){

long sum = 0;

for(int i=0;i

sum += numbers[i];

}

return sum;

}

}

样例2-代码

ExecutoreService提供了submit()方法。传递一个Callable,或Runnable,返回Future。假设Executor后台线程池还没有完毕Callable的计算,这调用返回Future对象的get()方法,会堵塞直到计算完毕。

package cn.fansunion.executorservice;

import java.util.ArrayList;

import java.util.List;

import java.util.concurrent.Callable;

import java.util.concurrent.ExecutionException;

import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;

import java.util.concurrent.Future;

import java.util.concurrent.FutureTask;

//并发计算数组的和,“同步”求和

public class ConcurrentCalculator {

private ExecutorService exec;

//这个地方,纯粹是“一厢情愿”,“并行执行”不受咱们控制。取决于操作系统的“态度”

private int cpuCoreNumber;

private List> tasks = new ArrayList>();

class SumCalculator implements Callable {

private int[] numbers;

private int start;

private int end;

public SumCalculator(final int[] numbers, int start, int end) {

this.numbers = numbers;

this.start = start;

this.end = end;

}

public Long call() throws Exception {

Long sum = 0L;

for (int i = start; i < end; i++) {

sum += numbers[i];

}

return sum;

}

}

public ConcurrentCalculator() {

cpuCoreNumber = Runtime.getRuntime().availableProcessors();

exec = Executors.newFixedThreadPool(cpuCoreNumber);

}

public Long sum(final int[] numbers) {

// 依据CPU核心个数拆分任务,创建FutureTask并提交到Executor

for (int i = 0; i < cpuCoreNumber; i++) {

int increment = numbers.length / cpuCoreNumber + 1;

int start = increment * i;

int end = increment * i + increment;

if (end > numbers.length)

end = numbers.length;

SumCalculator subCalc = new SumCalculator(numbers, start, end);

FutureTask task = new FutureTask(subCalc);

tasks.add(task);

if (!exec.isShutdown()) {

exec.submit(task);

}

}

return getResult();

}

/**

* 迭代每一个仅仅任务,获得部分和。相加返回

*/

public Long getResult() {

Long result = 0l;

for (Future task : tasks) {

try {

// 假设计算未完毕则堵塞

Long subSum = task.get();

result += subSum;

} catch (InterruptedException e) {

e.printStackTrace();

} catch (ExecutionException e) {

e.printStackTrace();

}

}

return result;

}

public void close() {

exec.shutdown();

}

}

样例3-代码

在刚在的样例中。getResult()方法的实现过程中。迭代了FutureTask的数组,假设任务还没有完毕则当前线程会堵塞。

假设我们希望随意字任务完毕后就把其结果加到result中。而不用依次等待每一个任务完毕,能够使CompletionService。

生产者submit()执行的任务。使用者take()已完毕的任务。并依照完毕这些任务的顺序处理它们的结果 。

也就是调用CompletionService的take方法是,会返回按完毕顺序放回任务的结果。

CompletionService内部维护了一个堵塞队列BlockingQueue,假设没有任务完毕。take()方法也会堵塞。

改动刚才的样例2,使用CompletionService:package cn.fansunion.executorservice;

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;

//并发计算数组的和。“异步”求和

public class ConcurrentCalculatorAsync {

private ExecutorService exec;

private CompletionService completionService;

//这个地方。纯粹是“一厢情愿”。“并行执行”不受咱们控制,取决于操作系统的“态度”

private int cpuCoreNumber;

class SumCalculator implements Callable {

private int[] numbers;

private int start;

private int end;

public SumCalculator(final int[] numbers, int start, int end) {

this.numbers = numbers;

this.start = start;

this.end = end;

}

public Long call() throws Exception {

Long sum = 0l;

for (int i = start; i < end; i++) {

sum += numbers[i];

}

return sum;

}

}

public ConcurrentCalculatorAsync() {

cpuCoreNumber = Runtime.getRuntime().availableProcessors();

exec = Executors.newFixedThreadPool(cpuCoreNumber);

completionService = new ExecutorCompletionService(exec);

}

public Long sum(final int[] numbers) {

// 依据CPU核心个数拆分任务。创建FutureTask并提交到Executor

for (int i = 0; i < cpuCoreNumber; i++) {

int increment = numbers.length / cpuCoreNumber + 1;

int start = increment * i;

int end = increment * i + increment;

if (end > numbers.length){

end = numbers.length;

}

SumCalculator subCalc = new SumCalculator(numbers, start, end);

if (!exec.isShutdown()) {

completionService.submit(subCalc);

}

}

return getResult();

}

/**

* 迭代每一个仅仅任务。获得部分和。相加返回

*/

public Long getResult() {

Long result = 0l;

for (int i = 0; i < cpuCoreNumber; i++) {

try {

Long subSum = completionService.take().get();

result += subSum;

System.out.println("subSum="+subSum+",result="+result);

} catch (InterruptedException e) {

e.printStackTrace();

} catch (ExecutionException e) {

e.printStackTrace();

}

}

return result;

}

public void close() {

exec.shutdown();

}

}

执行代码

package cn.fansunion.executorservice;

import java.math.BigDecimal;

//数组求和3个Demo

public class ArraySumDemo {

public static void main(String[] args) {

int n = 200000000;

int[] numbers = new int[n];

for(int i=1;i<=n;i++){

numbers[i-1]=i;

}

basic(numbers);

long time = System.currentTimeMillis();

concurrentCaculatorAsync(numbers);

long endTime=System.currentTimeMillis();

System.out.println("多核并行计算,异步相加:"+time(time,endTime));

long time2 = System.currentTimeMillis();

concurrentCaculator(numbers);

long endTime2=System.currentTimeMillis();

System.out.println("多核并行计算,同步相加:"+time(time2,endTime2));

}

private static void basic(int[] numbers) {

long time1 = System.currentTimeMillis();

long sum=BasicCaculator.sum(numbers);

long endTime1 = System.currentTimeMillis();

System.out.println("单线程:"+time(time1,endTime1));

System.out.println("Sum:"+sum);

}

private static double time(long time, long endTime) {

long costTime = endTime-time;

BigDecimal bd = new BigDecimal(costTime);

//本来想着,把毫秒转换成秒的,最后发现计算太快了

BigDecimal unit = new BigDecimal(1L);

BigDecimal s= bd.divide(unit,3);

return s.doubleValue();

}

//并行计算,“同步”求和

private static void concurrentCaculator(int[] numbers) {

ConcurrentCalculator calc = new ConcurrentCalculator();

Long sum = calc.sum(numbers);

System.out.println(sum);

calc.close();

}

//并行计算,“异步”求和

private static void concurrentCaculatorAsync(int[] numbers) {

ConcurrentCalculatorAsync calc = new ConcurrentCalculatorAsync();

Long sum = calc.sum(numbers);

System.out.println("Sum:"+sum);

calc.close();

}

}

控制台输出

单线程:93.0

Sum:20000000100000000

subSum=3750000175000002,result=3750000175000002

subSum=1250000075000001,result=5000000250000003

subSum=6250000275000003,result=11250000525000006

subSum=8749999574999994,result=20000000100000000

Sum:20000000100000000

多核并行计算,异步相加:786.0

20000000100000000

多核并行计算。同步相加:650.0

个人看法:3段代码的时间仅供參考,没有排除干扰因素。

总的来说,单线程执行更快一些,应该是因为“数组求和”本身,并不须要其他额外资源。不会堵塞。

而多线程,反而添加了“线程调度”的时间开销。

还能够看出,CPU计算还是非常快的。“200000000”2亿个整数相加。用了不到0.1秒的时间。

插曲

最開始看代码的时候,误解了。

以为“依据CPU核心个数拆分任务”。这个时候的“多线程”就是“并行”了。

实际上。不一定,除了要看CPU的核数,还要看操作系统的分配。

// 依据CPU核心个数拆分任务,创建FutureTask并提交到Executor

for (int i = 0; i < cpuCoreNumber; i++) {

}

最開始。我还在考虑“单线程”、“多核并行+多线程并发”、“单核+多线程并发”,等好几种情况来实现“数组求和”。

最后。感觉自己还是想多了。“并行”应该不受自己控制,仅仅能控制是“单线程”或者“多线程”。

“java并发编程-Executor框架”这篇文章中的“样例:并行计算数组的和。

”这句话,误导了我,根本不能保证是“并行计算”。

友情提示:网络上的文章,仅供參考学习,须要自己的推断。

关于Java-多核-并行-多线程。我初步觉得“多线程能够并行执行,但不受我们自己的控制,取决于操作系统”。

网友的一些看法:

看法1:

java线程能够在执行在多个cpu核上吗?

我是一直都以为这个问题的答案是肯定的,也就是说能够执行在多核上。

可是有一天见到这种一个理论。我就顿时毁三观了。

JVM在操作系统中是作为一个进程的,java全部的线程都执行自这个JVM进程中,

所以说java线程某个时间仅仅可能执行在一个核上。

这个说法对我的打击太大了,我不能接受。于是就開始多方求证。网上搜索 和朋友一起讨论。

终于证实了java线程是能够执行在多核上的,为什么呢?

以下一句话将惊醒梦中人:

现代os都将线程作为最小调度单位。进程作为资源分配的最小单位。

在windows中进程是不活动的,

仅仅是作为线程的容器。

也就是说。java中的全部线程确实在JVM进程中,可是CPU调度的是进程中的线程。

看法2:

JAVA中的多线程能在多CPU机器上并行执行吗?注意。我说的不是并发执行哦 。

我们用java写一个多线程程序,就启动了一个JVM进程,所以这些线程都是在这一个JVM进程之中的,我不知道同一时刻,能不能有多个CPU执行同一进程。进而并行执行这同一进程中的不同线程?一直非常疑惑

你的思路是对的,CPU就是为了迎合操作系统的多线程从而提高系统的计算效率.可是详细分配任务到各个内核中去执行的并不是JAVA与JVM而是操作系统.

也就是说,你所执行的多线程,可能会被分配到同一个CPU内核中执行.也可能非配到不同的cpu中执行.假设能够控制CPU的分配,那也应该是操作系统的api才干实现的了。

我用JAVA创建了一个线程,这时候有主线程和子线程都在执行,那意思双核CPU有可能在同一时刻点并行执行这两个线程咯?

我翻了好多JAVA的有关多线程的章节。似乎都没有说道多核CPU执行JAVA多线程,貌似都是已单核为例解说的,所以我一直觉得可能都是并发的而不是并行的?

不是,你要将你的软件线程和计算机的CPU处理线程区分开呀.简单说,你是无法控制CPU对于任务的分配的.

很多其他代码演示样例:

http://git.oschina.net/fansunion/Concurrent(逐步更新中)

參考资料:

java并发编程-Executor框架

http://www.iteye.com/topic/366591

java线程能够在执行在多个cpu核上吗?

http://blog.csdn.net/maosijunzi/article/details/42527553

JAVA中的多线程能在多CPU上并行执行吗?注意,我说的不是并发执行哦

http://zhidao.baidu.com/link?url=e11sEOSNFoLTfVyP-5FfpktIXEgbMQkbLAzvgh8mn4V16n_qQas89voj5gVhOEkho0jRA7fp_vbnElxKgeQCDrOxGkcu6xAWaUniqpcWg33

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值