zoukankan      html  css  js  c++  java
  • JAVA并行异步编程,线程池+FutureTask

    java 在JDK1.5中引入一个新的并发包java.util.concurrent 该包专门为java处理并发而书写。

    在java中熟悉的使用多线程的方式为两种?继续Thread类,实现Runnale。两种方式简单方便。

    在Jdk1.5之后其实有第三种方式实现方式,采用并发包中的 Callable接口 FuruteTask类 以及 ExecutorService接口。

    说新的实现方式之前先来说讨论一下传统的java执行过程

    首先一个简单的程序一个方法生成随机数,在生成随机数的方法执行中,睡眠1s模拟方法调用时候的耗时,把结果放进集合中,最后算到总结果。

    public 
      class Count{
        public static void main(String[] args) throws InterruptedException {
          long start = System.currentTimeMillis();
               Count count = new Count();
               List<Integer> res = new ArrayList<>();
               res.add(count.random());
               res.add(count.random());
               res.add(count.random());
               res.add(count.random());
               int totle =0;
               for (int i = 0; i < res.size(); i++) {
                 totle+=res.get(i);
               }
              long end = System.currentTimeMillis();
               System.out.println("运算结束 耗时:"+(end-start)+"ms  totle:"+totle );
               System.out.println("退出main线程!");
             }
        int random() throws InterruptedException{
          Thread.sleep(1000); //
          return new Random().nextInt(100);
        }
      }

        结果如下

    运算结束 耗时:4000ms  totle:66
    退出main线程!

         在传统的编写中是单线程的操作,串行操作,当调用方法count.random(),main线程被阻塞起来,直到睡眠时间到达,自动唤醒main线程。

    那么有没有什么办法来减少main主线程的阻塞时间呢?能不能让这几个操作并行进行呢?如果是并行运行带来什么好处呢?

    并行带来的好处,可以减少比较多的方法执行时间,如random()方法并行计算,也就是说main线程的阻塞只有1s,阻塞时间减少75%

    java为我们提供了多线程机制,利用多线程我们可以实现方法的并行运算,实现多线程的办法,实现Runnable接口重新run,继承Thread 重写run;因为run方法的并没有返回值,我们手动的去创建大量的线程并且维护线程是件很讨厌的事情,并且创建线程也是非常耗费资源的操作,能不能有一个池子来帮我们管理线程呢?有没有一个类能够透明的去进行透明并发的异步操作呢?这个在JDK1.5之前是没有的,在1,5之后出现了一个新包,专门为并发而开发的包,使用并发包中提供的类和接口,将很轻易的实现。并发编程。

    import java.util.ArrayList;
    import java.util.List;
    import java.util.Random;
    import java.util.concurrent.Callable;
    import java.util.concurrent.ExecutionException;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    import java.util.concurrent.FutureTask;
    
     public class TestMain {
      public static void main(String[] args) throws InterruptedException, ExecutionException {
        new  TestMain().exec();
      }
      void exec() throws InterruptedException, ExecutionException{
        //进行异步任务列表
        List<FutureTask<Integer>> futureTasks = new ArrayList<FutureTask<Integer>>();
        //线程池 初始化十个线程 和JDBC连接池是一个意思 实现重用 
        ExecutorService executorService = Executors.newFixedThreadPool(10);
        long start = System.currentTimeMillis();
        //类似与run方法的实现 Callable是一个接口,在call中手写逻辑代码
        Callable<Integer> callable = new Callable<Integer>() {
          @Override
          public Integer call() throws Exception {
            Integer res = new Random().nextInt(100);
            Thread.sleep(1000);
            System.out.println("任务执行:获取到结果 :"+res);
            return  res;
          }
        };
        
        for(int i=0;i<10;i++){
          //创建一个异步任务
          FutureTask<Integer> futureTask = new FutureTask<Integer>(callable);
          futureTasks.add(futureTask);
          //提交异步任务到线程池,让线程池管理任务 特爽把。
                 //由于是异步并行任务,所以这里并不会阻塞
          executorService.submit(futureTask); 
        }
        
        int count = 0;
           for (FutureTask<Integer> futureTask : futureTasks) {
             //futureTask.get() 得到我们想要的结果 
             //该方法有一个重载get(long timeout, TimeUnit unit) 第一个参数为最大等待时间,第二个为时间的单位
             count+= futureTask.get();
      }
         long end = System.currentTimeMillis();
         System.out.println("线程池的任务全部完成:结果为:"+count+",main线程关闭,进行线程的清理");
         System.out.println("使用时间:"+(end-start)+"ms");
         //清理线程池 
         executorService.shutdown();
        
      }
    }

    上述情况如果不用异步并行,程序将至少睡眠10s

    使用之后的结果

    任务执行:获取到结果 :99
    任务执行:获取到结果 :78
    任务执行:获取到结果 :52
    任务执行:获取到结果 :78
    任务执行:获取到结果 :97
    任务执行:获取到结果 :8
    任务执行:获取到结果 :97
    任务执行:获取到结果 :3
    任务执行:获取到结果 :78
    任务执行:获取到结果 :31
    线程池的任务全部完成:结果为:621,main线程关闭,进行线程的清理
    使用时间:1004ms 

    我们试着把线程池的大小减少一半

    任务执行:获取到结果 :87
    任务执行:获取到结果 :60
    任务执行:获取到结果 :13
    任务执行:获取到结果 :18
    任务执行:获取到结果 :8
    任务执行:获取到结果 :86
    任务执行:获取到结果 :52
    任务执行:获取到结果 :4
    任务执行:获取到结果 :23
    任务执行:获取到结果 :16
    线程池的任务全部完成:结果为:367,main线程关闭,进行线程的清理
    使用时间:2017ms
    

    好玩吧 时间延长了一半。

  • 相关阅读:
    [LeetCode] 60. Permutation Sequence 序列排序
    [LeetCode] 31. Next Permutation 下一个排列
    [LeetCode] 47. Permutations II 全排列 II
    [LeetCode] 46. Permutations 全排列
    [LeetCode] 77. Combinations 全组合
    利用 Json.Net 将对象转换成Json
    使用sqlmetal工具自动生成SQL数据库的Linq类文件
    SharePoint 2013 设置 显示详细错误信息 修改位置总结
    本地访问Vmware虚机Web网站
    Web项目HttpContext.Current 为空
  • 原文地址:https://www.cnblogs.com/CoolJayson/p/7767052.html
Copyright © 2011-2022 走看看