1. 程式人生 > >Java多執行緒實現加法計算

Java多執行緒實現加法計算

採用多執行緒的方式實現從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");
    }