采用多线程的方式实现从1到N的和
1.直接顺序计算
public static void Sum(int N){
long start1 = System.currentTimeMillis();
long sum = 0;
for(int i=1; i<=N; i++){
sum += i;
}
long end1 = System.currentTimeMillis();
System.out.println("串行计算耗时:" + (end1 - start1) + " ms");
System.out.println("串行计算的结果:" + sum);
}
public static void main(String[] args) throws ExecutionException,
InterruptedException, BrokenBarrierException
{
//实现多线程加法求和
int N = 90000000;
//mutilSum(arr, N, 2);
Sum(N);
//countDownLatchSum(N, 9);
//cyclicBarrierSum2(N, 9);
}
运行结果如下:
2.线程池和Callable
利用Callable接口可以在线程中返回结果,利用Future可以阻塞获取结果,利用线程池可以批量产生多个线程
public static class SumThread implements Callable<Long>{
private long start;
private long end;
public SumThread(long start, long end){
this.start = start;
this.end = end;
}
@Override
public Long call() throws Exception {
long sum = 0L;
for(long i = start; i<end; i++){
sum += i;
}
return sum;
}
}
//使用线程池+Callable接口
public static void mutilSum(int N, int numThread) throws ExecutionException,
InterruptedException {
ExecutorService executor = Executors.newFixedThreadPool(numThread);
long start1 = System.currentTimeMillis();
List<Future<Long>> ans = new ArrayList<>();
for(int i=0; i<numThread; i++){
Future<Long> a = executor.submit(
new SumThread(i*N/numThread, (i+1)*N/numThread));
ans.add(a);
}
long sum = 0;
for (Future<Long> i : ans) {
long tmp = i.get();
System.out.println("线程 "+i +" 的结果是: "+tmp);
sum += tmp;
}
//并行计算
long end1 = System.currentTimeMillis();
System.out.println("并行计算耗时:" + (end1 - start1) + " ms");
System.out.println("并行计算的结果:" + sum);
}
依次改变线程池的数量1,2,3,5,9,20,结果如下:
由测试可知,增加线程池得数量可以减少计算时间,然而当线程池数量过大时,计算性能会下降,这主要涉及到线程池的使用以及cpu核数与线程调度的关系,当线程数量过大时,会进行频繁得上下文切换,导致cpu不能充分进行计算。
3.CountDownLatch
public static class SumCThread implements Runnable{
private long start;
private long end;
private long[] result;
private CountDownLatch cdl;
private int num;
public SumCThread(CountDownLatch cdl, long[] result, long start, long end,
int num){
this.result = result;
this.start = start;
this.end = end;
this.cdl = cdl;
this.num = num;
}
@Override
public void run(){
long sum = 0L;
for(long i=start; i<end; i++){
sum += i;
}
result[num] = sum;
cdl.countDown();
}
}
//每个线程结果怎么返回 线程如何等待最终求值
//使用CountDownLatch
public static void countDownLatchSum(int N, int numThread) throws
InterruptedException {
long start1 = System.currentTimeMillis();
CountDownLatch cdl = new CountDownLatch(numThread);
long[] result = new long[numThread];
long sum = 0L;
for(int i=0; i<numThread; i++){
new Thread(
new SumCThread(cdl, result,i*N/numThread, (i+1)*N/numThread, i))
.start();
}
cdl.await();
for(int i=0; i<numThread; i++){
sum += result[i];
}
//并行计算
long end1 = System.currentTimeMillis();
System.out.println("并行计算耗时:" + (end1 - start1) + " ms");
System.out.println("并行计算的结果:" + sum);
}
依次改变线程池数量1,3,9
4.CyclicBarrier
使用CycleBarrier来进行线程同步,待所有线程计算完毕,在主线程计算中间数组之和,求出最后结果
public static class SumCBThread implements Runnable{
private long start;
private long end;
private long[] result;
private CyclicBarrier cb;
private int num;
public SumCBThread(CyclicBarrier cb, long[] result, long start, long end,
int num){
this.result = result;
this.start = start;
this.end = end;
this.cb = cb;
this.num = num;
}
@Override
public void run(){
long sum = 0L;
for(long i=start; i<end; i++){
sum += i;
}
result[num] = sum;
try {
cb.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}
}
//使用同步屏障来实现
public static void cyclicBarrierSum(int N, int numThread) throws
BrokenBarrierException, InterruptedException {
long start1 = System.currentTimeMillis();
CyclicBarrier cb = new CyclicBarrier(numThread+1);
long[] result = new long[numThread];
long sum = 0L;
for(int i=0; i<numThread; i++){
new Thread(
new SumCBThread(cb, result,i*N/numThread, (i+1)*N/numThread, i))
.start();
}
cb.await();
for(int i=0; i<numThread; i++){
sum += result[i];
}
//并行计算
long end1 = System.currentTimeMillis();
System.out.println("并行计算耗时:" + (end1 - start1) + " ms");
System.out.println("并行计算的结果:" + sum);
}
使用CycleBarrier构造器,传入线程同步时进行操作的Runnable接口方法
public static class SumCB implements Runnable{
long[] result;
public SumCB(long[] result){
this.result = result;
}
@Override
public void run() {
long sum = 0L;
for(int i=0; i<result.length; i++){
sum += result[i];
}
System.out.println("并行计算的结果:" + sum);
}
}
public static void cyclicBarrierSum2(int N, int numThread) throws
BrokenBarrierException, InterruptedException {
long start1 = System.currentTimeMillis();
long[] result = new long[numThread];
CyclicBarrier cb = new CyclicBarrier(numThread, new SumCB(result));
for(int i=0; i<numThread; i++){
new Thread(
new SumCBThread(cb, result,i*N/numThread, (i+1)*N/numThread, i))
.start();
}
//并行计算
long end1 = System.currentTimeMillis();
System.out.println("并行计算耗时:" + (end1 - start1) + " ms");
}
5.ForkJoin
利用ForkJoin框架来fork拆分,分段计算,然后执行join来合并最终结果
public class ForkJoinCalculate extends RecursiveTask<Long> {
private long start;
private long end;
private static final long THRESHOLD = 10000;
public ForkJoinCalculate(long start, long end){
this.start = start;
this.end = end;
}
@Override
protected Long compute() {
long length = end - start;
if(length <= THRESHOLD){
long sum = 0;
for(long i=start; i<=end; i++){
sum += i;
}
return sum;
}else{
long middle = (start + end) >> 1;
ForkJoinCalculate left = new ForkJoinCalculate(start, middle);
left.fork();
ForkJoinCalculate right = new ForkJoinCalculate(middle+1, end);
right.fork();
return left.join() + right.join();
}
}
public static void main(String[] args) {
Instant start = Instant.now();
ForkJoinPool pool = new ForkJoinPool();
ForkJoinTask<Long> task = new ForkJoinCalculate(1, 100000L);
Long sum = pool.invoke(task);
System.out.println(sum);
Instant end = Instant.now();
System.out.println(Duration.between(start, end).getNano());
}
}