• [并发编程]并发编程第二篇:利用并发编程,实现计算大量数据的和


    利用并发编程,实现计算大量数据的和

    实现代码:

    package tj.pojo.generate.main;
    
    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<Future<Long>> tasks = new ArrayList<Future<Long>>();
    
        // 内部类
        class SumCalculator implements Callable<Long> {
            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;
            }
            @Override
            public Long call() throws Exception {
                Long sum = 0L;
                for (int i = start; i < end; i++) {
                    sum += numbers[i];
                }
                System.out.println(String.format("%s~%s的和为%s", start, end, sum));
                return sum;
            }
    
        }
    
        public ConcurrentCalculator() {
            cpuCoreNumber = Runtime.getRuntime().availableProcessors();
            System.out.println("CPU核心数:" + cpuCoreNumber);
            exec = Executors.newFixedThreadPool(cpuCoreNumber);
    
        }
    
        public Long sum(final int[] numbers) {
            for (int i = 0; i < cpuCoreNumber; i++) {
                int increment = numbers.length / cpuCoreNumber + 1;
                int start = increment * i;
                int end = start + increment;
                if (end > numbers.length) {
                    end = numbers.length;
                }
                SumCalculator task = new SumCalculator(numbers, start, end);
    
                FutureTask<Long> future = new FutureTask<Long>(task);
                tasks.add(future);
                System.out.println("添加一个任务,总任务数为:" + tasks.size());
                if (!exec.isShutdown()) {
                    exec.submit(future);
                    // ExecutoreService提供了submit()方法,传递一个Callable,或Runnable,返回Future。
                    // exec.submit(task);
                }
            }
            System.out.println("任务分配完成,总任务数为:" + tasks.size());
            return getResult();
        }
    
        public Long getResult() {
            Long sums = 0L;
            for (Future<Long> task : tasks) {
                try {
                    Long sum = task.get();
                    sums += sum;
                    System.out.println("当前总合计:" + sums);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (ExecutionException e) {
                    e.printStackTrace();
                }
            }
            return sums;
        }
    
        public void close() {
            exec.shutdown();
        }
    }

    其中,在代码的第62行~第64行,由于不了解ExecutoreService.submit(Runnable task)方法的功能。

    同时FutureTask<Long> future和SumCalculator task都实现了Runnable接口,造成代码调用时,进程一直不结束。

    传递了FutureTask<Long> future才正确执行。

                    exec.submit(future);
                    // ExecutoreService提供了submit()方法,传递一个Callable,或Runnable,返回Future。
                    // exec.submit(task);

    测试方法:

    public static void test() {
            int[] numbers = new int[100];
            for (int i = 0; i < 100; i++) {
                numbers[i] = i + 1;
            }
            tj.pojo.generate.main.ConcurrentCalculator cc = new tj.pojo.generate.main.ConcurrentCalculator();
            Long sum = cc.sum(numbers);
            System.out.println("1~100的和为" + sum);
            cc.close();
        }

    FutureTask的实现代码:

    public class FutureTask<V> implements RunnableFuture<V>

    FutureTask类实现了RunnableFuture接口,RunnableFuture接口的实现代码:

    public interface RunnableFuture<V> extends Runnable, Future<V> {

        void run();

    }

    可以看出RunnableFuture继承了Runnable接口和Future接口,而FutureTask实现了RunnableFuture接口。

    所以它既可以作为Runnable被线程执行,又可以作为Future得到Callable的返回值。

    事实上,FutureTask是Future接口的一个唯一实现类。

    并发编程的两种实现形式:

    1):使用Callable+Future获取执行结果

    public class Test {
        public static void main(String[] args) {
            ExecutorService executor = Executors.newCachedThreadPool();
            Task task = new Task();
            Future<Integer> result = executor.submit(task);
            executor.shutdown();
             
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e1) {
                e1.printStackTrace();
            }
             
            System.out.println("主线程在执行任务");
             
            try {
                System.out.println("task运行结果"+result.get());
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                e.printStackTrace();
            }
             
            System.out.println("所有任务执行完毕");
        }
    }
    class Task implements Callable<Integer>{
        @Override
        public Integer call() throws Exception {
            System.out.println("子线程在进行计算");
            Thread.sleep(3000);
            int sum = 0;
            for(int i=0;i<100;i++)
                sum += i;
            return sum;
        }
    }

    2):使用Callable+FutureTask获取执行结果

    public class Test {
        public static void main(String[] args) {
            //第一种方式
            ExecutorService executor = Executors.newCachedThreadPool();
            Task task = new Task();
            FutureTask<Integer> futureTask = new FutureTask<Integer>(task);
            executor.submit(futureTask);
            executor.shutdown();
             
            //第二种方式,注意这种方式和第一种方式效果是类似的,只不过一个使用的是ExecutorService,一个使用的是Thread
            /*Task task = new Task();
            FutureTask<Integer> futureTask = new FutureTask<Integer>(task);
            Thread thread = new Thread(futureTask);
            thread.start();*/
             
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e1) {
                e1.printStackTrace();
            }
             
            System.out.println("主线程在执行任务");
             
            try {
                System.out.println("task运行结果"+futureTask.get());
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                e.printStackTrace();
            }
             
            System.out.println("所有任务执行完毕");
        }
    }
    class Task implements Callable<Integer>{
        @Override
        public Integer call() throws Exception {
            System.out.println("子线程在进行计算");
            Thread.sleep(3000);
            int sum = 0;
            for(int i=0;i<100;i++)
                sum += i;
            return sum;
        }
    }
  • 相关阅读:
    抽象与接口的综合练习
    java构造函数能否被继承,为什么?
    题解 【USACO 4.2.1】草地排水
    题解 【NOI2010】超级钢琴
    题解 [USACO Mar08] 奶牛跑步
    题解 【NOIP2016】魔法阵
    题解 对称二叉树
    题解 【NOIP2014】解方程
    题解 【NOIP2010】关押罪犯
    题解 贪吃蛇
  • 原文地址:https://www.cnblogs.com/Candies/p/5692389.html
Copyright © 2020-2023  润新知